【发布时间】:2021-12-03 12:37:30
【问题描述】:
我正在尝试找到一种解决方案来在同步上下文中调用异步函数。
以下是我的参考资料:
- Python call callback after async function is done
- When using asyncio, how do you allow all running tasks to finish before shutting down the event loop
- https://docs.python.org/zh-cn/3/library/asyncio-task.html
- RuntimeError: This event loop is already running in python
- call async function in main function
但我发现,asyncio.get_event_loop() 在执行 asyncio.run() 时失败,这是我重现此问题的代码:
import asyncio
async def asyncfunction(n):
print(f'before sleep in asyncfunction({ n })')
await asyncio.sleep(1)
print(f'after sleep in asyncfunction({ n })')
return f'result of asyncfunction({ n })'
def callback(r):
print(f'inside callback, got: {r}')
r0 = asyncio.run(asyncfunction(0)) # cause following asyncio.get_event_loop() fail.
callback(r0)
print('sync code following asyncio.run(0)')
r1 = asyncio.run(asyncfunction(1)) # but following asyncio.run() still works.
callback(r1)
print('sync code following asyncio.run(1)')
async def wrapper(n):
r = await asyncfunction(n)
callback(r)
asyncio.get_event_loop().create_task(wrapper(2)) #fail if there is asyncio.run() before
print('sync code following loop.create_task(2)')
#RuntimeError: There is no current event loop in thread 'MainThread'.
asyncio.get_event_loop().create_task(wrapper(3)) #the second call works if there is no asyncio.run() before
print('sync code following loop.create_task(3)')
# main
_all = asyncio.gather(*asyncio.all_tasks(asyncio.get_event_loop()))
asyncio.get_event_loop().run_until_complete(_all)
我认为这可能是因为事件循环被某种东西“消耗”了,asyncio.set_event_loop(asyncio.new_event_loop()) 可能是一种解决方法,但我不确定 这是否是最终用户设置的预期用途手动事件循环。我也想知道这里的为什么和一切是如何发生的。
看了asyncio.run的部分源码。我知道为什么会这样。
但我仍然想知道在同步上下文中调用异步函数的预期方式是什么?
以下代码似乎有效(在每次asyncio.run() 调用后设置一个新的事件循环):
asyncio.run(asyncfunction())
asyncio.set_event_loop(asyncio.new_event_loop())
但这有点奇怪,似乎不是预期的方式。
【问题讨论】:
-
根据
asyncio.run的文档:“这个函数总是创建一个新的事件循环并在最后关闭它。” -
@dirn 感谢您指出这一点。我现在添加了更多描述和子问题。
标签: python python-3.x python-asyncio