设置回调并且(大部分)忘记 . 它们不适用于从中获取结果所需的内容 . 这就是为什么生成的句柄只允许你取消回调(不再需要这个回调),仅此而已 .
如果您需要在另一个线程中等待来自asyncio管理的协同程序的结果,请使用协同程序并使用asyncio.run_coroutine_threadsafe()将其安排为任务;这给你一个Future() instance,然后你可以等待完成 .
但是,使用 run_coroutine_threadsafe() 停止循环确实需要循环来处理比实际能够运行的更多回调;否则 run_coroutine_threadsafe() 返回的 Future 将不会被通知它所安排的任务的状态更改 . 您可以通过在关闭循环之前在线程B中运行 asyncio.sleep(0) 到 loop.run_until_complete() 来解决此问题:
def thread_A():
# ...
# when done, schedule the asyncio loop to exit
future = asyncio.run_coroutine_threadsafe(shutdown_loop(loop), loop)
future.result() # wait for the shutdown to complete
print("Thread A out")
def thread_B(loop):
print("Thread B")
asyncio.set_event_loop(loop)
loop.run_forever()
# run one last noop task in the loop to clear remaining callbacks
loop.run_until_complete(asyncio.sleep(0))
loop.close()
print("Thread B out")
async def shutdown_loop(loop):
print("Stopping loop")
loop.stop()
当然,这有点hacky,并且取决于回调管理和跨线程任务调度的内部不会改变 . 作为默认的 asyncio 实现,运行单个noop任务足以进行多轮回调,从而创建更多回调,但是替代循环实现可能会以不同方式处理 .
因此,对于关闭循环,您可能最好使用基于线程的协调:
def thread_A():
# ...
callback_event = threading.Event()
loop.call_soon_threadsafe(callback, loop, callback_event)
callback_event.wait() # wait for the shutdown to complete
print("Thread A out")
def thread_B(loop):
print("Thread B")
asyncio.set_event_loop(loop)
loop.run_forever()
loop.close()
print("Thread B out")
def callback(loop, callback_event):
print("Stopping loop")
loop.stop()
callback_event.set()