简体   繁体   English

在 class __init__ 上定义 aiohttp ClientSession 供以后重用

[英]Define aiohttp ClientSession on class __init__ for later reuse

I want to create a persistent session that last until the program ends, I have the following code.我想创建一个持续到程序结束的持久 session,我有以下代码。

import asyncio
import aiohttp
import atexit

class Session:
    def __init__(self):
        self._session = aiohttp.ClientSession()
        atexit.register(self._close_session)

    async def get(self, url):
        response = await self._session.request("GET", url)
        return await response.json()

    def _close_session(self):
        asyncio.run(self._session.close())


async def pullit():
    print(await session.get("https://raw.communitydragon.org/latest/game/data/characters/aatrox/aatrox.bin.json"))

session = Session()

asyncio.run(pullit()) # THIS THROWS: Timeout context manager should be used inside a task
asyncio.get_event_loop().run_until_complete(pullit()) #THIS RUNS OK

This throws me an exception on the self._session.request line with Timeout context manager should be used inside a task , I've searched for other answers but it is still giving the same error.这在self._session.request行上引发了一个异常,其中Timeout context manager should be used inside a task ,我已经搜索了其他答案,但它仍然给出相同的错误。

Question: What is the cause of this error?问题:这个错误的原因是什么? If I want to open a session that last the lifetime of a program, and I need it to be defined inside a class (obligatory), how would that be?如果我想打开一个持续程序生命周期的 session,并且我需要在 class(强制性)中定义它,那会怎样?

Extra: Currently I am using atexit to close the session when the program ends (refer above code), is this a good way of doing so?额外:目前我正在使用atexit在程序结束时关闭 session(请参阅上面的代码),这是一个方法吗? if not, what is a better practice如果没有,什么是更好的做法

UPDATE: I found the solution to this, it was to use asyncio.get_event_loop().run_until_complete(...) , but isn't asyncio.run() the same as above?更新:我找到了解决方案,它是使用asyncio.get_event_loop().run_until_complete(...) ,但asyncio.run()不是和上面一样吗? why does one runs without problem and the 3.7+ asyncio.run() doesn't run?为什么一个运行没有问题而 3.7+ asyncio.run()不运行?


UPDATE 2: I ended up with the following code:更新2:我最终得到以下代码:

#runner.py
import aiohttp
import asyncio


class Runner:
    def __init__(self, coro):
        self.coro = coro

    async def run(self):
        session = aiohttp.ClientSession()
        client.start_session(session)
        await self.coro
        client.close_session()
        await session.close()


def run(coro):
    runner = Runner(coro)
    return asyncio.run(runner.run())
#client.py
class Client:
    def __init__(self):
        self._session = None

    async def get(self, url):
        response = await self._session.request("GET", url)
        return await response.json()

    def start_session(self, session):
        self._session = session

    def close_session(self):
        self._session = None
from .runner import run
from .client import Client

client = Client()

async def pullit():
    print(await client.get("https://raw.communitydragon.org/latest/game/data/characters/aatrox/aatrox.bin.json"))

run(pullit())

OK, this runs and everything but after it runs it throws me RuntimeError: Event loop is closed , which I never closed a loop.好的,这会运行,但运行后会抛出RuntimeError: Event loop is closed ,我从未关闭过循环。

Here's my solution to your problem:这是我对您的问题的解决方案:

import aiohttp
import asyncio
import atexit


class HTTPClient():
    def __init__(self):
        self._session = aiohttp.ClientSession()
        atexit.register(self._shutdown)
        print('session created')

    async def request(self, *args, **kwargs):
        async with self._session.request(*args, **kwargs) as response:
            return (response.status, await response.text())

    def _shutdown(self):
        asyncio.run(self._session.close())
        print('session closed')


async def main():
    http_client = HTTPClient()
    status, text = await http_client.request(url='http://example.com', method='GET')
    print(status)


asyncio.run(main())

On the other hand, I guess, the best approach should be some wrapper around the following code:另一方面,我想,最好的方法应该是对以下代码的一些包装:

async with aiohttp.ClientSession() as session:
    # perform all needed http calls inside
    pass

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

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