18.5.2. 事件循环 — Python 文档

来自菜鸟教程
Python/docs/3.6/library/asyncio-eventloops
跳转至:导航、​搜索

18.5.2. 事件循环

源代码: :source:`Lib/asyncio/events.py`

18.5.2.1. 事件循环函数

以下函数是访问全局策略方法的便捷快捷方式。 请注意,这提供了对默认策略的访问,除非在流程执行的早期通过调用 set_event_loop_policy() 设置了替代策略。

asyncio.get_event_loop()
相当于调用 get_event_loop_policy().get_event_loop()
asyncio.set_event_loop(loop)
相当于调用 get_event_loop_policy().set_event_loop(loop)
asyncio.new_event_loop()
相当于调用 get_event_loop_policy().new_event_loop()


18.5.2.2. 可用的事件循环

asyncio 目前提供了两种事件循环的实现:SelectorEventLoopProactorEventLoop

class asyncio.SelectorEventLoop

基于 选择器 模块的事件循环。 AbstractEventLoop 的子类。

使用平台上可用的最有效的选择器。

在 Windows 上,仅支持套接字(例如:不支持管道):请参阅 select MSDN 文档。

class asyncio.ProactorEventLoop

使用“I/O 完成端口”又名 IOCP 的 Windows Proactor 事件循环。 AbstractEventLoop 的子类。

可用性:Windows。

在 Windows 上使用 ProactorEventLoop 的示例:

import asyncio, sys

if sys.platform == 'win32':
    loop = asyncio.ProactorEventLoop()
    asyncio.set_event_loop(loop)

18.5.2.3. 平台支持

asyncio 模块被设计为可移植的,但每个平台仍然有细微的差异,可能不支持所有的 asyncio 功能。

18.5.2.3.1。 视窗

Windows 事件循环的常见限制:

SelectorEventLoop 具体限制:

  • 使用 SelectSelector 仅支持套接字,限制为 512 个套接字。
  • add_reader()add_writer() 只接受套接字的文件描述符
  • 不支持管道(例如:connect_read_pipe()connect_write_pipe()
  • 不支持子进程 (例如:subprocess_exec()subprocess_shell()

ProactorEventLoop 具体限制:

Windows 上单调时钟的分辨率通常在 15.6 毫秒左右。 最佳分辨率为 0.5 毫秒。 分辨率取决于硬件(HPET 的可用性)和 Windows 配置。 参见 asyncio 延迟调用

3.5 版更改:ProactorEventLoop 现在支持 SSL。


18.5.2.3.2. Mac OS X

自 Mavericks (Mac OS 10.9) 以来,像 PTY 这样的字符设备才得到很好的支持。 Mac OS 10.5 及更早版本根本不支持它们。

在 Mac OS 10.6、10.7 和 10.8 上,默认事件循环是 SelectorEventLoop,它使用 selectors.KqueueSelectorselectors.KqueueSelector 在这些版本上不支持字符设备。 SelectorEventLoop 可以与 SelectSelectorPollSelector 一起使用,以在这些版本的 Mac OS X 上支持字符设备。 例子:

import asyncio
import selectors

selector = selectors.SelectSelector()
loop = asyncio.SelectorEventLoop(selector)
asyncio.set_event_loop(loop)

18.5.2.4. 事件循环策略和默认策略

事件循环管理被抽象为 policy 模式,为自定义平台和框架提供最大的灵活性。 在流程的整个执行过程中,单个全局策略对象根据调用上下文管理流程可用的事件循环。 策略是实现 AbstractEventLoopPolicy 接口的对象。

对于 asyncio 的大多数用户来说,策略永远不必明确处理,因为默认的全局策略就足够了(见下文)。

模块级函数 get_event_loop()set_event_loop() 提供对默认策略管理的事件循环的便捷访问。


18.5.2.5. 事件循环策略接口

事件循环策略必须实现以下接口:

class asyncio.AbstractEventLoopPolicy

事件循环策略。

get_event_loop()

获取当前上下文的事件循环。

返回一个实现 AbstractEventLoop 接口的事件循环对象。 如果从协程调用,它返回当前运行的事件循环。

如果没有为当前上下文设置事件循环并且当前策略未指定创建事件循环,则引发异常。 它绝不能返回 None

在 3.6 版中更改。

set_event_loop(loop)

将当前上下文的事件循环设置为 loop

new_event_loop()

根据此策略的规则创建并返回一个新的事件循环对象。

如果需要将此循环设置为当前上下文的事件循环,则必须显式调用 set_event_loop()

默认策略将上下文定义为当前线程,并管理每个与 asyncio 交互的线程的事件循环。 如果当前线程还没有与之关联的事件循环,则默认策略的 get_event_loop() 方法在从主线程调用时创建一个,否则引发 RuntimeError


18.5.2.6. 访问全局循环策略

asyncio.get_event_loop_policy()
获取当前事件循环策略。
asyncio.set_event_loop_policy(policy)
设置当前事件循环策略。 如果policyNone,则恢复默认策略。


18.5.2.7. 自定义事件循环策略

要实现新的事件循环策略,建议您将具体的默认事件循环策略 DefaultEventLoopPolicy 子类化并覆盖要更改其行为的方法,例如:

class MyEventLoopPolicy(asyncio.DefaultEventLoopPolicy):

    def get_event_loop(self):
        """Get the event loop.

        This may be None or an instance of EventLoop.
        """
        loop = super().get_event_loop()
        # Do something with loop ...
        return loop

asyncio.set_event_loop_policy(MyEventLoopPolicy())