Asyncio您如何使用run_forever?

时间:2018-08-01 21:06:48

标签: python python-asyncio

我想做什么:

  1. 具有一个异步事件循环,该循环会加速
  2. 该循环被传递到我的系统中的各种类上,以在其上安排协程
  3. 那个循环还用于处理事件的响应(即,我有一个队列,一些事件处理代码会将一个项目放置在该队列上,并在该队列上等待等待get()的单独的协同例程来处理这些值)
  4. 有一个主线程“拥有”该循环并负责创建循环,并且在系统关闭时将取消循环上的所有正在运行的任务,并关闭并停止循环(干净地关闭)

我的理解是由于#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()

1 个答案:

答案 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回调和协程调用循环函数很好,因为它们将始终在与事件循环运行所在的线程中运行。