简体   繁体   English

aiohttp 如何在类中保存持久的 ClientSession?

[英]aiohttp how to save a persistent ClientSession in a class?

I'm writing a class that will do http requests using aiohttp.我正在编写一个使用 aiohttp 执行 http 请求的类。 According to the docs I should not to create a ClientSession per request, so I want to reuse the same session.根据文档,我不应该为每个请求创建一个 ClientSession,所以我想重用同一个会话。

code:代码:

class TestApi:
   def __init__(self):
      self.session = aiohttp.ClientSession()

   # async defs methods from here 

When doing做的时候

TestApi()

I get the error: Unclosed client session .我收到错误:未Unclosed client session

What is the solution to persist the ClientSession object?持久化ClientSession对象的解决方案是什么?

The expression TestApi() on a line by itself creates a TestApi object and immediately throws it away. TestApi()的表达式TestApi()创建一个TestApi对象并立即将其丢弃。 aiohttp complaints that the session was never closed (either by leaving an async with block or with an explicit call to close() ), but even without the warning it doesn't make sense not to assign the API object to a variable where it will be actually used. aiohttp抱怨会话从未关闭(通过async with块或显式调用close()离开async with ),但即使没有警告,不将 API 对象分配给变量也是没有意义的被实际使用。

To reuse the session, your code needs to have access to the session, or to an object that holds it:要重用会话,您的代码需要有权访问会话或持有它的对象:

async def fetch(url):
    async with aiohttp.request('GET', url) as resp:
        resp.raise_for_status()
        return await resp.read()

async def main():
    url1_data, url2_data = asyncio.gather(
        fetch('http://url1'), fetch('http://url2'))
    url3_data, url4_data = asyncio.gather(
        fetch('http://url3'), fetch('http://url4'))

One option is to add a session parameter to fetch (and other functions) and consistently call it with a session created in main() .一种选择是添加一个session参数来fetch (和其他函数)并使用在main()创建的会话一致地调用它。 A better option is to create an API class and convert the global functions like fetch to methods:更好的选择是创建一个 API 类并将全局函数(如fetch转换为方法:

class Http:
    async def __aenter__(self):
        self._session = aiohttp.ClientSession()
        return self

    async def __aexit__(self, *err):
        await self._session.close()
        self._session = None

    async def fetch(self, url):
        async with self._session.get(url) as resp:
            resp.raise_for_status()
            return await resp.read()

main() can still exist as a function, but it can consistently use the object that holds the session: main()仍然可以作为函数存在,但它可以始终如一地使用持有会话的对象:

async def main():
    async with Http() as http:
        url1_data, url2_data = await asyncio.gather(
            http.fetch('http://url1'), http.fetch('http://url2'))
        url3_data, url4_data = await asyncio.gather(
            http.fetch('http://url3'), http.fetch('http://url4'))

In the above code, the async with statement is used to ensure that the session is closed whenever the scope is left.在上面的代码中, async with语句用于确保只要离开范围就关闭会话。

Actually, I don't see anything fundamentally wrong with your code. 实际上,我认为你的代码没有任何根本性的错误。

Except, when your TestApi object is destroyed, likely when your program finishes, you will need to call the close function. 除了,当您的TestApi对象被销毁时,可能在程序完成时,您需要调用close函数。 Otherwise you get this warning. 否则你会收到此警告。

(And that is a coroutine that needs to be awaited: https://docs.aiohttp.org/en/stable/client_reference.html ) (这是一个需要等待的协程: https//docs.aiohttp.org/en/stable/client_reference.html

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM