[英]Define aiohttp ClientSession on class __init__ for later reuse
我想創建一個持續到程序結束的持久 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
這在self._session.request
行上引發了一個異常,其中Timeout context manager should be used inside a task
,我已經搜索了其他答案,但它仍然給出相同的錯誤。
問題:這個錯誤的原因是什么? 如果我想打開一個持續程序生命周期的 session,並且我需要在 class(強制性)中定義它,那會怎樣?
額外:目前我正在使用atexit
在程序結束時關閉 session(請參閱上面的代碼),這是一個好方法嗎? 如果沒有,什么是更好的做法
更新:我找到了解決方案,它是使用asyncio.get_event_loop().run_until_complete(...)
,但asyncio.run()
不是和上面一樣嗎? 為什么一個運行沒有問題而 3.7+ asyncio.run()
不運行?
更新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())
好的,這會運行,但運行后會拋出RuntimeError: Event loop is closed
,我從未關閉過循環。
這是我對您的問題的解決方案:
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())
另一方面,我想,最好的方法應該是對以下代碼的一些包裝:
async with aiohttp.ClientSession() as session:
# perform all needed http calls inside
pass
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.