【发布时间】:2019-02-19 16:00:31
【问题描述】:
我有一个类,其中包含一个 aiohttp.ClientSession 对象。
通常在你使用时
async with aiohttp.ClientSession() as session:
# some code
会话将在会话的 __aexit__ 方法被调用后关闭。
我不能使用上下文管理器,因为我想在对象的整个生命周期内保持会话持久。
这行得通:
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>
【问题讨论】:
-
你应该
await asyncio.shield()不要打电话 -
@yorodm:
__del__不是协程,所以你不能在那里使用await。传递给shield()的协程无论如何都被安排为任务,在这里等待与否无关紧要。 -
@MartijnPieters 对快速评论感到抱歉,“你应该等待 asyncio.shield()` 我的意思是把它移到
__del__以外的地方,但很高兴知道任务已经安排好了跨度>
标签: python python-asyncio aiohttp contextmanager