在退出时自动关闭 aiohttp 会话 python
Automatically close an aiohttp session at exit python
我希望能够使用 atexit 自动关闭 aiohttp 会话,但我无法弄清楚为什么这不起作用。
我有以前工作的代码,但是一旦我在模块外部和文件内部定义了事件循环,其中使用的模块就会中断。
简化版代码:
按预期工作,但 public 函数不是异步的
# main.py
import module
client = module.Client()
client.foo()
# module/client.py
import asyncio
import atexit
import aiohttp
class Client:
def __init__(self, loop=None):
self.loop = asyncio.get_event_loop() if loop is None else loop
atexit.register(self.close)
self._session = aiohttp.ClientSession(loop=self.loop)
def _run(self, future):
return self.loop.run_until_complete(future)
def close(self):
self._run(self._session.close())
def foo(self):
...
self._run(...)
...
没有按预期工作,public 函数是异步的并且循环在 main.py
中定义
# main.py
import module
import asyncio
async def main():
client = module.Client()
await client.foo()
asyncio.run(main())
# module/client.py
import asyncio
import atexit
import aiohttp
class Client:
def __init__(self, loop=None):
self.loop = asyncio.get_event_loop() if loop is None else loop
atexit.register(self.close)
self._session = aiohttp.ClientSession(loop=self.loop)
def _run(self, future):
return self.loop.run_until_complete(future)
def close(self):
self._run(self._session.close())
async def foo(self):
...
await ...
...
第二个代码段引发错误Event loop is closed.
我基于 Whosebug 上的类似问题尝试过的解决方案给出了错误 the event loop is already running
或 there is no current event loop in thread.
是否有解决方案可以在其他地方创建事件循环时自动关闭ClientSession? public 函数是异步的,如果不是等待其中的所有内容,这有关系吗?
任何帮助将不胜感激,谢谢!
我很确定 atexit
没有工作,因为您正在尝试 运行 异步代码,因此在循环关闭之前它不会被调用,您可能需要一个with
对象通过添加
async def __aexit__(self, *error_details):
# await but don't return, if exit returns truethy value it suppresses exceptions.
await self._run(self._session.close())
async def __aenter__(self):
return self
到 Client
class 然后主代码可以使用 async with
确保客户端在主函数内关闭:
async def main():
async with module.Client() as client:
await client.foo()
这使得 __aexit__
方法在 with
块完成时被调用,以确保客户端关闭,类似于使用 with 语句关闭文件等方式。
否则你想要 .close()
到 return 可等待对象,这样你就可以在主函数中调用它并等待关闭事件循环完成:
async def main():
client = module.Client()
await client.foo()
await client.close() # requires .close() to return the awaitable
我希望能够使用 atexit 自动关闭 aiohttp 会话,但我无法弄清楚为什么这不起作用。
我有以前工作的代码,但是一旦我在模块外部和文件内部定义了事件循环,其中使用的模块就会中断。
简化版代码:
按预期工作,但 public 函数不是异步的
# main.py
import module
client = module.Client()
client.foo()
# module/client.py
import asyncio
import atexit
import aiohttp
class Client:
def __init__(self, loop=None):
self.loop = asyncio.get_event_loop() if loop is None else loop
atexit.register(self.close)
self._session = aiohttp.ClientSession(loop=self.loop)
def _run(self, future):
return self.loop.run_until_complete(future)
def close(self):
self._run(self._session.close())
def foo(self):
...
self._run(...)
...
没有按预期工作,public 函数是异步的并且循环在 main.py
中定义# main.py
import module
import asyncio
async def main():
client = module.Client()
await client.foo()
asyncio.run(main())
# module/client.py
import asyncio
import atexit
import aiohttp
class Client:
def __init__(self, loop=None):
self.loop = asyncio.get_event_loop() if loop is None else loop
atexit.register(self.close)
self._session = aiohttp.ClientSession(loop=self.loop)
def _run(self, future):
return self.loop.run_until_complete(future)
def close(self):
self._run(self._session.close())
async def foo(self):
...
await ...
...
第二个代码段引发错误Event loop is closed.
我基于 Whosebug 上的类似问题尝试过的解决方案给出了错误 the event loop is already running
或 there is no current event loop in thread.
是否有解决方案可以在其他地方创建事件循环时自动关闭ClientSession? public 函数是异步的,如果不是等待其中的所有内容,这有关系吗?
任何帮助将不胜感激,谢谢!
我很确定 atexit
没有工作,因为您正在尝试 运行 异步代码,因此在循环关闭之前它不会被调用,您可能需要一个with
对象通过添加
async def __aexit__(self, *error_details):
# await but don't return, if exit returns truethy value it suppresses exceptions.
await self._run(self._session.close())
async def __aenter__(self):
return self
到 Client
class 然后主代码可以使用 async with
确保客户端在主函数内关闭:
async def main():
async with module.Client() as client:
await client.foo()
这使得 __aexit__
方法在 with
块完成时被调用,以确保客户端关闭,类似于使用 with 语句关闭文件等方式。
否则你想要 .close()
到 return 可等待对象,这样你就可以在主函数中调用它并等待关闭事件循环完成:
async def main():
client = module.Client()
await client.foo()
await client.close() # requires .close() to return the awaitable