8.13. 循环控制

大多数 asyncio 脚本从不直接操作事件循环——asyncio.run() 就足够了。本页面针对那些它不够用的情况介绍 Loop 接口:安装异常处理器、以不同于 run 的生命周期来运行循环,或者保留循环对象以进行监测。

8.13.1. 获取循环

  • asyncio.get_event_loop()——返回 Loop 对象。无论在协程内部还是外部调用都是安全的。

  • asyncio.new_event_loop()——在 MicroPython 上,它会 重置现有循环的状态,而不是创建一个新循环。这一点值得重申:每个程序恰好只有一个事件循环。

除了 Loop 上的方法和 asyncio.run() 之外,没有用于 运行 循环的 API。

8.13.2. 直接运行循环

对于几乎所有应用程序而言,asyncio.run() 都是正确的入口点。为那些它不适用的情况提供了两个 Loop 方法。

  • run_until_complete()——给定一个可等待对象,运行循环直到该可等待对象完成,然后返回其结果。相当于一次单独的 asyncio.run() 调用,但省去了循环的拆除步骤。

  • run_forever()——运行循环,直到某个任务内部调用了 stop()。没有顶层可等待对象;应用程序应当在调用 run_forever 之前通过 asyncio.create_task() 调度它所需要的一切。

与之配套的方法是 stop()(请求在当前任务完成后停止循环)和 close()(释放循环的资源)。

8.13.3. 循环侧的任务创建

  • create_task()——与 asyncio.create_task() 是同一种操作。提供这个自由函数是为了让应用程序代码在常见情况下不需要持有循环引用;提供这个方法则是为了那些已经持有循环引用的监测代码。

8.13.4. 异常处理器

当某个任务抛出了协程调用链中无人捕获的异常时,循环会调用一个处理器——一个典型的情况是应用程序用 asyncio.create_task() 创建了一个任务却从未 await 它。默认处理器会通过 sys.stderr 打印回溯信息;异常 页面展示了如何将它替换为自定义处理器。

  • set_exception_handler()——安装一个自定义处理器。该处理器是一个可调用对象 handler(loop, context),其中 context 是一个至少包含 'message' 键、通常还包含 'exception''future' 键的字典。

  • get_exception_handler()——返回当前已安装的处理器,如果使用的是默认处理器,则返回 None

  • default_exception_handler()——内置处理器。在某个想要 同时 运行默认行为的自定义处理器内部很有用(例如,既记录到闪存 打印回溯信息)。

  • call_exception_handler()——用一个手工构建的 context 字典来运行当前已安装的处理器。它主要由循环本身使用;应用程序很少需要它。