gpt4 book ai didi

python - 如何在异步循环关闭之前等待对象的 __del__ 完成?

转载 作者:太空宇宙 更新时间:2023-11-04 08:28:35 24 4
gpt4 key购买 nike

我有一个包含 aiohttp.ClientSession 对象的类。

通常当你使用

async with aiohttp.ClientSession() as session:  
# some code

session 将关闭,因为 session 的 __aexit__ 方法被调用。

我不能使用上下文管理器,因为我想在对象的整个生命周期内保持 session 持久。

这个有效:

import asyncio
import aiohttp

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

def __del__(self):
# Close connection when this object is destroyed
print('In __del__ now')
asyncio.shield(self.session.__aexit__(None, None, None))



async def main():
api = MyAPI()

asyncio.run(main())

然而,如果在某个地方引发异常,事件循环会在 __aexit__ 方法完成之前关闭。我该如何克服这个问题?

堆栈跟踪:

Traceback (most recent call last):
File "/home/ron/.PyCharm2018.3/config/scratches/async.py", line 19, in <module>
asyncio.run(main())
File "/usr/local/lib/python3.7/asyncio/runners.py", line 43, in run
return loop.run_until_complete(main)
File "/usr/local/lib/python3.7/asyncio/base_events.py", line 568, in run_until_complete
return future.result()
File "/home/ron/.PyCharm2018.3/config/scratches/async.py", line 17, in main
raise ValueError
ValueError
In __del__ now
Exception ignored in: <function MyAPI.__del__ at 0x7f49982c0e18>
Traceback (most recent call last):
File "/home/ron/.PyCharm2018.3/config/scratches/async.py", line 11, in __del__
File "/usr/local/lib/python3.7/asyncio/tasks.py", line 765, in shield
File "/usr/local/lib/python3.7/asyncio/tasks.py", line 576, in ensure_future
File "/usr/local/lib/python3.7/asyncio/events.py", line 644, in get_event_loop
RuntimeError: There is no current event loop in thread 'MainThread'.
sys:1: RuntimeWarning: coroutine 'ClientSession.__aexit__' was never awaited
Unclosed client session
client_session: <aiohttp.client.ClientSession object at 0x7f49982c2e10>

最佳答案

不要使用 __del__ 钩子(Hook)来清理异步资源。你根本不能算它被调用,更不用说控制它何时被使用或者异步循环是否在那个时候仍然可用。你真的想明确地处理这个。

要么使 API 成为异步上下文管理器,要么在退出时使用 finally 处理程序显式清理资源,例如; withasync with 语句基本上旨在封装传统上在 finally block 中处理的资源清理。

我会在此处将 API 实例设为上下文管理器:

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

async def __aenter__(self):
return self

async def __aexit__(self, *excinfo):
await self.session.close()

请注意,ClientSession.__aexit__() 真正做的是在 self.close() 上等待,因此以上内容直接针对协程。

然后在你的主循环中使用它:

async def main():
async with MyAPI() as api:
pass

另一种选择是向 MyAPI 实例提供您自己的 session 对象,并在完成后自行负责关闭它:

class MyAPI:
def __init__(self, session):
self.session = session

async def main():
session = aiohttp.ClientSession()
try:
api = MyAPI(session)
# do things with the API
finally:
await session.close()

关于python - 如何在异步循环关闭之前等待对象的 __del__ 完成?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54770360/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com