当循环运行时,如何运行协同例程并等待同步函数产生的结果?
问题描述
我有一个类似愚弄的代码:
def render():
loop = asyncio.get_event_loop()
async def test():
await asyncio.sleep(2)
print("hi")
return 200
if loop.is_running():
result = asyncio.ensure_future(test())
else:
result = loop.run_until_complete(test())
当loop
没有运行时非常简单,只需使用loop.run_until_complete
,它会返回coro结果,但是如果循环已经在运行(我的阻塞代码运行在已经在运行循环的应用程序中),我不能使用loop.run_until_complete
,因为它会引发异常;当我调用asyncio.ensure_future
时,任务会被调度并运行,但我想在那里等待结果,有人知道怎么做吗?文档不太清楚如何执行此操作。
concurrent.futures.Future
调用set_result
,然后在我的阻塞代码上调用Future.result()
,但它不起作用,它在那里阻塞,并且不让任何其他东西运行。如有任何帮助,我们将不胜感激。
解决方案
要使用建议的设计实现runner
,您需要一种方法来单步执行在其中运行的回调的事件循环。Asyncioexplicitly forbids递归事件循环,因此此方法是死胡同。
考虑到该约束,您有两个选择:
- 使
render()
本身成为协程; - 在与运行异步事件循环的线程不同的线程中执行
render()
(及其调用方)。
假设不存在#1,您可以实现render()
的#2变体,如下所示:
def render():
loop = _event_loop # can't call get_event_loop()
async def test():
await asyncio.sleep(2)
print("hi")
return 200
future = asyncio.run_coroutine_threadsafe(test(), loop)
result = future.result()
请注意,您不能在render
中使用asyncio.get_event_loop()
,因为没有(也不应该)为该线程设置事件循环。相反,派生运行器线程的代码必须调用asyncio.get_event_loop()
并将其发送到线程,或者只是将其保留在全局变量或共享结构中。
相关文章