简体   繁体   English

Asyncio您如何使用run_forever?

[英]Asyncio How do you use run_forever?

What I want to do: 我想做的事:

  1. have an asyncio event loop that gets spun up 有一个异步事件循环,它会旋转
  2. that loop is passed to various classes in my system for scheduling coroutines on 该循环将传递到我的系统中的各种类上,以调度协程
  3. that loop is also used for handling the responses to events (ie, I have a Queue, some event handling code will place an item on that queue, and separate co-routines that await a get() on that queue to handle those values) 该循环还用于处理事件的响应(即,我有一个队列,一些事件处理代码会将一个项目放置在该队列上,并在该队列上等待等待get()的单独的协同例程来处理这些值)
  4. there is a main thread which "owns" the loop and is responsible for creating the loop, and at time of system shutdown will cancel any running tasks on the loop and close & stop the loop (cleanly shutdown) 有一个主线程“拥有”该循环并负责创建该循环,并且在系统关闭时将取消该循环上的所有正在运行的任务,并关闭和停止该循环(完全关闭)

My understanding is because of #3, something needs to call run_forever() on the loop to ensure that tasks get scheduled on the loop. 我的理解是由于#3,需要在循环上调用run_forever()以确保任务在循环上得到调度。 But if I call run_forever() then my main thread blocks, never to terminate. 但是,如果我调用run_forever()那么我的主线程就会阻塞,永远不会终止。

What I've tried: 我试过的

Spawn a thread, passing in the loop, and then call run_forever in the thread. 生成一个线程,在循环中传递,然后在该线程中调用run_forever This means though that my unit tests never finish. 这意味着尽管我的单元测试从未完成。 The gist: 要点:

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()

There are two possible approaches: you can run the event loop in the main thread or in a background thread. 有两种可能的方法:您可以在主线程或后台线程中运行事件循环。 If you run it in the main thread, you need to run_forever (or run_until_complete(main()) or equivalent) as the very last step of the program initialization. 如果在主线程中运行它,则需要在程序初始化的最后一步中运行run_forever (或run_until_complete(main())或同等功能)。 In that case the main thread will "block", but that's ok because its event loop will be live and respond to outside events, allowing the program to function. 在那种情况下,主线程将“阻塞”,但这是可以的,因为它的事件循环将继续运行并响应外部事件,从而允许程序运行。 A single "blocking" call to the event loop that dispatches coroutines and callbacks is how asyncio is designed to be run. 分派协程和回调的事件循环的单个“阻塞”调用是设计异步运行的方式。

In cases where this is impractical, such as programs that contain a large body of synchronous code, or those that already communicate between several threads, it is often a better idea to create a dedicated thread and run the event loop in it. 在不切实际的情况下,例如包含大量同步代码的程序,或者已经在多个线程之间进行通信的程序,通常最好创建一个专用线程并在其中运行事件循环。 In that case you must be very careful not to communicate with the event loop other than with calls to loop.call_soon_threadsafe() and asyncio.run_coroutine_threadsafe() . 在那种情况下,除了要调用loop.call_soon_threadsafe()asyncio.run_coroutine_threadsafe()之外,您必须非常小心不要与事件循环通信。 For example, __end_background_loop must be invoked using loop.call_soon_threadsafe(__end_background_loop) because it interacts with the tasks and the event loop. 例如, __end_background_loop必须通过调用loop.call_soon_threadsafe(__end_background_loop)因为它的任务和事件循环互动。 This applies to all interactions with the event loop - for example, calling loop.stop() from another thread is not allowed, it must be spelled as loop.call_soon_threadsafe(loop.stop) . 这适用于与事件循环的所有交互-例如,不允许从另一个线程调用loop.stop() ,必须将其拼写为loop.call_soon_threadsafe(loop.stop) Of course, calling loop functions from asyncio callbacks and coroutines is fine because those will always be run in the same thread the event loop runs in. 当然,从asyncio回调和协程调用循环函数很好,因为它们将始终在与事件循环运行所在的线程中运行。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM