我想做什么:
我的理解是由于#3的缘故,需要在循环上调用run_forever()
以确保任务在循环上得到调度。但是,如果我调用run_forever()
,那么我的主线程就会阻塞,永远不会终止。
我尝试过的事情:
生成一个线程,在循环中传递,然后在该线程中调用run_forever
。这意味着尽管我的单元测试从未完成。要点:
def __start_background_loop(loop):
def run_forever(loop):
loop.run_forever()
# because run_forever() will block the current thread, we spawn
# a subthread to issue that call in.
thread = Thread(target=run_forever, args=(loop,))
thread.start()
def __end_background_loop(loop):
for task in Task.all_tasks(loop):
task.cancel()
loop.stop()
答案 0 :(得分:3)
有两种可能的方法:您可以在主线程或后台线程中运行事件循环。如果在主线程中运行它,则需要run_forever
(或run_until_complete(main())
或同等功能)作为程序初始化的最后一步。在那种情况下,主线程将“阻塞”,但这是可以的,因为它的事件循环将继续运行并响应外部事件,从而允许程序运行。分派协程和回调的事件循环的单个“阻塞”调用就是设计异步运行的方式。
在不切实际的情况下,例如包含大量同步代码的程序,或者已经在多个线程之间进行通信的程序,通常最好创建一个专用线程并在其中运行事件循环。在这种情况下,您必须非常小心,不要与事件循环通信,而不能与对loop.call_soon_threadsafe()
和asyncio.run_coroutine_threadsafe()
的调用进行通信。例如,__end_background_loop
必须使用loop.call_soon_threadsafe(__end_background_loop)
来调用,因为它与任务和事件循环交互。这适用于与事件循环的所有交互-例如,不允许从另一个线程调用loop.stop()
,必须将其拼写为loop.call_soon_threadsafe(loop.stop)
。当然,从asyncio回调和协程调用循环函数很好,因为它们将始终在与事件循环运行所在的线程中运行。