18.5.1. 基本事件循环 — Python 文档

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

18.5.1. 基本事件循环

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

事件循环是 asyncio 提供的中央执行设备。 它提供多种设施,包括:

  • 注册、执行和取消延迟调用(超时)。
  • 为各种通信创建客户端和服务器 传输
  • 启动子进程和关联的 传输 以与外部程序通信。
  • 将代价高昂的函数调用委托给线程池。
class asyncio.BaseEventLoop
这个类是一个实现细节。 它是 AbstractEventLoop 的子类,并且可能是在 asyncio 中找到的具体事件循环实现的基类。 不应直接使用; 改用 AbstractEventLoopBaseEventLoop 不应被第三方代码子类化; 内部接口不稳定。
class asyncio.AbstractEventLoop

事件循环的抽象基类。

此类是 不是线程安全的

18.5.1.1. 运行事件循环

AbstractEventLoop.run_forever()

运行直到 stop() 被调用。 如果在调用 run_forever() 之前调用 stop(),这将轮询一次 I/O 选择器,超时为零,运行所有为响应 I/O 事件而安排的回调(以及那些已经安排好的),然后退出。 如果在 run_forever() 运行时调用 stop(),这将运行当前批次的回调,然后退出。 请注意,在这种情况下,回调安排的回调将不会运行; 它们将在下次调用 run_forever() 时运行。

在 3.5.1 版中更改。

AbstractEventLoop.run_until_complete(future)

运行直到 Future 完成。

如果参数是 协程对象 ,则由 ensure_future() 包裹。

返回 Future 的结果,或引发其异常。

AbstractEventLoop.is_running()
返回事件循环的运行状态。
AbstractEventLoop.stop()

停止运行事件循环。

这会导致 run_forever() 在下一个合适的机会退出(有关更多详细信息,请参见此处)。

在 3.5.1 版中更改。

AbstractEventLoop.is_closed()

如果事件循环已关闭,则返回 True

版本 3.4.2 中的新功能。

AbstractEventLoop.close()

关闭事件循环。 循环不能运行。 挂起的回调将丢失。

这会清除队列并关闭执行程序,但不会等待执行程序完成。

这是幂等且不可逆的。 在此之后不应调用其他方法。


18.5.1.2. 通话

大多数 asyncio 函数不接受关键字。 如果要将关键字传递给回调,请使用 functools.partial()。 例如,loop.call_soon(functools.partial(print, "Hello", flush=True)) 将调用 print("Hello", flush=True)

笔记

functools.partial()lambda 函数更好,因为 asyncio 可以检查 functools.partial() 对象在调试模式下显示参数,而 lambda 函数的代表性较差。


AbstractEventLoop.call_soon(callback, \*args)

安排尽快调用回调。 当控制返回到事件循环时,在 call_soon() 返回后调用回调。

这作为 FIFO 队列运行,回调按它们注册的顺序调用。 每个回调只会被调用一次。

回调之后的任何位置参数都将在调用时传递给回调。

返回一个 asyncio.Handle 的实例,可用于取消回调。

使用 functools.partial 将关键字传递给回调

AbstractEventLoop.call_soon_threadsafe(callback, \*args)

call_soon(),但线程安全。

请参阅文档的 并发和多线程 部分。


18.5.1.3. 延迟呼叫

事件循环有自己的内部时钟来计算超时。 使用哪个时钟取决于(特定于平台的)事件循环实现; 理想情况下,它是一个单调时钟。 这通常是与 time.time() 不同的时钟。

笔记

超时(相对 延迟 或绝对 when)不应超过 1 天。


AbstractEventLoop.call_later(delay, callback, *args)

安排 callback 在给定的 delay 秒(整数或浮点数)后调用。

返回一个 asyncio.Handle 的实例,可用于取消回调。

callback 每次调用 call_later() 时只会被调用一次。 如果两个回调被安排在完全相同的时间,则未定义将首先调用哪个。

可选的位置 args 将在调用时传递给回调。 如果您希望使用一些命名参数调用回调,请使用闭包或 functools.partial()

使用 functools.partial 将关键字传递给回调

AbstractEventLoop.call_at(when, callback, *args)

使用与 AbstractEventLoop.time() 相同的时间参考,安排 callback 在给定的绝对时间戳 when(整数或浮点数)上调用。

此方法的行为与 call_later() 相同。

返回一个 asyncio.Handle 的实例,可用于取消回调。

使用 functools.partial 将关键字传递给回调

AbstractEventLoop.time()
根据事件循环的内部时钟,以 float 值的形式返回当前时间。

也可以看看

asyncio.sleep() 功能。


18.5.1.4. 期货

AbstractEventLoop.create_future()

创建一个附加到循环的 asyncio.Future 对象。

这是在 asyncio 中创建期货的首选方式,因为事件循环实现可以提供 Future 类的替代实现(具有更好的性能或检测)。

版本 3.5.2 中的新功能。


18.5.1.5. 任务

AbstractEventLoop.create_task(coro)

安排 协程对象 的执行:将其包装在未来。 返回一个 Task 对象。

第三方事件循环可以使用它们自己的 Task 子类来实现互操作性。 在这种情况下,结果类型是 Task 的子类。

这个方法是在 Python 3.4.2 中添加的。 使用 async() 函数也支持较旧的 Python 版本。

版本 3.4.2 中的新功能。

AbstractEventLoop.set_task_factory(factory)

设置一个由 AbstractEventLoop.create_task() 使用的任务工厂。

如果 factoryNone 将设置默认任务工厂。

如果 factory 是一个 callable,它应该有一个匹配 (loop, coro) 的签名,其中 loop 将是对活动事件循环的引用,[ X157X]coro 将是一个协程对象。 可调用对象必须返回 asyncio.Future 兼容对象。

版本 3.4.4 中的新功能。

AbstractEventLoop.get_task_factory()

返回一个任务工厂,如果使用默认工厂,则返回 None

版本 3.4.4 中的新功能。


18.5.1.6. 创建连接

18.5.1.7. 创建监听连接

18.5.1.8. 观察文件描述符

在带有 SelectorEventLoop 的 Windows 上,仅支持套接字句柄(例如:不支持管道文件描述符)。

在带有 ProactorEventLoop 的 Windows 上,不支持这些方法。

AbstractEventLoop.add_reader(fd, callback, \*args)

开始观察文件描述符以获取读取可用性,然后使用指定参数调用 回调

使用 functools.partial 将关键字传递给回调

AbstractEventLoop.remove_reader(fd)
停止监视文件描述符以获取读取可用性。
AbstractEventLoop.add_writer(fd, callback, \*args)

开始观察文件描述符以获取写入可用性,然后使用指定参数调用 回调

使用 functools.partial 将关键字传递给回调

AbstractEventLoop.remove_writer(fd)
停止监视文件描述符以获取写入可用性。

watch a file descriptor for read events 示例使用低级 AbstractEventLoop.add_reader() 方法注册套接字的文件描述符。


18.5.1.9. 低级套接字操作

18.5.1.10。 解析主机名

18.5.1.11。 连接管道

在带有 SelectorEventLoop 的 Windows 上,不支持这些方法。 使用 ProactorEventLoop 在 Windows 上支持管道。

也可以看看

AbstractEventLoop.subprocess_exec()AbstractEventLoop.subprocess_shell() 方法。


18.5.1.12。 UNIX 信号

可用性:仅限 UNIX。

AbstractEventLoop.add_signal_handler(signum, callback, \*args)

为信号添加处理程序。

如果信号编号无效或无法捕获,则引发 ValueError。 如果设置处理程序出现问题,则引发 RuntimeError

使用 functools.partial 将关键字传递给回调

AbstractEventLoop.remove_signal_handler(sig)

删除信号的处理程序。

如果删除了信号处理程序,则返回 True,否则返回 False

也可以看看

信号模块。


18.5.1.13。 执行者

Executor(线程池或进程池)中调用函数。 默认情况下,事件循环使用线程池执行器 (ThreadPoolExecutor)。

AbstractEventLoop.set_default_executor(executor)
设置run_in_executor()使用的默认执行器。


18.5.1.14。 错误处理 API

允许自定义如何在事件循环中处理异常。

AbstractEventLoop.set_exception_handler(handler)

handler 设置为新的事件循环异常处理程序。

如果 handlerNone,将设置默认异常处理程序。

如果 handler 是一个可调用对象,它应该具有与 (loop, context) 匹配的签名,其中 loop 将是对活动事件循环的引用,context将是一个 dict 对象(有关上下文的详细信息,请参阅 call_exception_handler() 文档)。

AbstractEventLoop.get_exception_handler()

返回异常处理程序,如果正在使用默认处理程序,则返回 None

版本 3.5.2 中的新功能。

AbstractEventLoop.default_exception_handler(context)

默认异常处理程序。

当发生异常并且未设置异常处理程序时调用它,并且可以由想要遵循默认行为的自定义异常处理程序调用。

context 参数的含义与 call_exception_handler() 中的含义相同。

AbstractEventLoop.call_exception_handler(context)

调用当前事件循环异常处理程序。

context 是一个 dict 对象,包含以下键(稍后可能会引入新键):

  • 'message':错误信息;

  • “异常”(可选):异常对象;

  • 'future'(可选):asyncio.Future 实例;

  • 'handle'(可选):asyncio.Handle 实例;

  • 'protocol'(可选):Protocol 实例;

  • 'transport'(可选):Transport 实例;

  • 'socket'(可选):socket.socket 实例。

笔记

注意:此方法不应在子类事件循环中重载。 对于任何自定义异常处理,请使用 set_exception_handler() 方法。


18.5.1.15。 调试模式

AbstractEventLoop.get_debug()

获取事件循环的调试模式(bool)。

如果环境变量 PYTHONASYNCIODEBUG 设置为非空字符串,则默认值为 True,否则为 False

版本 3.4.2 中的新功能。

AbstractEventLoop.set_debug(enabled: bool)

设置事件循环的调试模式。

版本 3.4.2 中的新功能。

也可以看看

asyncio 调试模式。


18.5.1.16。 服务器

class asyncio.Server

服务器侦听套接字。

AbstractEventLoop.create_server() 方法和 start_server() 函数创建的对象。 不要直接实例化类。

close()

停止服务:关闭监听套接字并将 sockets 属性设置为 None

代表现有传入客户端连接的套接字保持打开状态。

服务器异步关闭,使用wait_closed()协程等待服务器关闭。

sockets

服务器正在侦听的 socket.socket 对象列表,如果服务器关闭,则为 None


18.5.1.17。 处理

class asyncio.Handle
AbstractEventLoop.call_soon()AbstractEventLoop.call_soon_threadsafe()AbstractEventLoop.call_later().AbstractEventLoop.call_later()返回的回调包装对象)
cancel()
取消通话。 如果回调已被取消或执行,则此方法无效。


18.5.1.18。 事件循环示例

18.5.1.18.1。 Hello World with call_soon()

使用 AbstractEventLoop.call_soon() 方法安排回调的示例。 回调显示 "Hello World" 然后停止事件循环:

import asyncio

def hello_world(loop):
    print('Hello World')
    loop.stop()

loop = asyncio.get_event_loop()

# Schedule a call to hello_world()
loop.call_soon(hello_world, loop)

# Blocking call interrupted by loop.stop()
loop.run_forever()
loop.close()

也可以看看

Hello World 协程 示例使用了 协程


18.5.1.18.2. 使用 call_later() 显示当前日期

每秒显示当前日期的回调示例。 回调使用 AbstractEventLoop.call_later() 方法在 5 秒内重新调度自身,然后停止事件循环:

import asyncio
import datetime

def display_date(end_time, loop):
    print(datetime.datetime.now())
    if (loop.time() + 1.0) < end_time:
        loop.call_later(1, display_date, end_time, loop)
    else:
        loop.stop()

loop = asyncio.get_event_loop()

# Schedule the first call to display_date()
end_time = loop.time() + 5.0
loop.call_soon(display_date, end_time, loop)

# Blocking call interrupted by loop.stop()
loop.run_forever()
loop.close()

也可以看看

协程显示当前日期 示例使用 协程


18.5.1.18.3。 观察文件描述符以获取读取事件

等到文件描述符使用 AbstractEventLoop.add_reader() 方法接收到一些数据,然后关闭事件循环:

import asyncio
try:
    from socket import socketpair
except ImportError:
    from asyncio.windows_utils import socketpair

# Create a pair of connected file descriptors
rsock, wsock = socketpair()
loop = asyncio.get_event_loop()

def reader():
    data = rsock.recv(100)
    print("Received:", data.decode())
    # We are done: unregister the file descriptor
    loop.remove_reader(rsock)
    # Stop the event loop
    loop.stop()

# Register the file descriptor for read event
loop.add_reader(rsock, reader)

# Simulate the reception of data from the network
loop.call_soon(wsock.send, 'abc'.encode())

# Run the event loop
loop.run_forever()

# We are done, close sockets and the event loop
rsock.close()
wsock.close()
loop.close()

也可以看看

使用协议注册一个打开的套接字以等待数据 示例使用由 AbstractEventLoop.create_connection() 方法创建的低级协议。

注册一个打开的套接字以使用流等待数据 示例使用由 open_connection() 函数在协程中创建的高级流。


18.5.1.18.4。 为 SIGINT 和 SIGTERM 设置信号处理程序

使用 AbstractEventLoop.add_signal_handler() 方法为信号 SIGINTSIGTERM 注册处理程序:

import asyncio
import functools
import os
import signal

def ask_exit(signame):
    print("got signal %s: exit" % signame)
    loop.stop()

loop = asyncio.get_event_loop()
for signame in ('SIGINT', 'SIGTERM'):
    loop.add_signal_handler(getattr(signal, signame),
                            functools.partial(ask_exit, signame))

print("Event loop running forever, press Ctrl+C to interrupt.")
print("pid %s: send SIGINT or SIGTERM to exit." % os.getpid())
try:
    loop.run_forever()
finally:
    loop.close()

此示例仅适用于 UNIX。