python3 asyncio官方文档中文版

mac2022-06-30  22

事件循环基类事件循环基类 事件循环是由asyncio提供的核心执行装置。它提供了多种服务,包括:

注册、执行和关闭延时调用(超时) 为各种通信创建客户端和服务端传输 为一个外部程序通信启动子进程和相关的传输 把高成本的函数调用委托到线程池 class asyncio.BaseEventLoop    此类是一个实现细节。此类是AbstractEventLoop的子类,是你在asyncio中找到的具体事件循环类的基类。它不应该被直接使用,而是使用AbstractEventLoop来代替它。BaseEventLoop不应该被第三方代码继承,它的内部接口并不稳定。

class asyncio.AbstractEventLoop    事件循环抽象基类。    这个类不是线程安全的。

1.1. 运行事件循环 AbstractEventLoop.run_forever()    一直运行直到stop()被调用。如果stop()在run_forever()之前被调用,它将轮询一次I/O selector(timeout为0),然后运行所有响应I/O事件的回调(以及那些已经被安排的回调),然后退出。如果stop()在run_forever()运行时被调用,它将运行当前的一批回调然后退出。请注意,那些被回调函数安排的回调不会在这种情况下运行;它们将会在下一次run_forever被调用时运行。 改动于3.5.1版本。

AbstractEventLoop.run_until_complete(future)    一直运行直到future运行完成。    如果参数是一个协程对象,它将被ensure_future()打包。    返回Future的结果,或者引发它的异常。

AbstractEventLoop.stop()    停止运行事件循环。    它将在一个适当的时机使得run_forever()退出。 改动于3.5.1版本。

AbstractEventLoop.is_closed()    当事件循环关闭时返回True。 新增于3.4.2版本。

AbstractEventLoop.close()    关闭事件循环。这个事件循环必须没有在运行。挂起的回调将会丢失。    此方法清空队列、关闭执行器,且不会等待执行器运行结束。    此方法是幂等且不可逆的。在此方法调用之后不应该调用任何其他方法。

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)    安排尽快调用这个callback(回调)。这个callback会在call_soon()返回、当控制权返回事件循环时被调用。    这个操作是一个先入先出队列,多个call_soon()注册了多个callback会按照它们的顺序依次被调用。每个callback都只会被调用一次。    callback后面的所有参数会在callback被调用时传递给callback。    返回值是asyncio.Handle的一个实例,用于中止这个callback。    (可以使用functools.partial()来给callback传递参数)

AbstractEventLoop.call_soon_threadsafe(callback, *args)    类似call_soon(),但是是线程安全的。    可以参考使用asyncio开发的 并发和多线程 段落。

1.3. 延时调用 事件循环有自己的内部时钟用于计算超时。这个时钟依赖于(特定平台的)事件循环来执行;理想情况下它是一个单调时钟(monotonic clock)。通常它是一个不同于time.time()的时钟。

注意:超时(相对延时或绝对时刻)不应该超过一天。

AbstractEventLoop.call_later(delay, callback, *args)    安排一个callback在delay秒之后被调用(delay可以是int和float)。    返回值是asyncio.Handle的一个实例,用于中止这个callback。    每次调用call_later()都有callback将被调用一次。如果多个回调被安排在同一时刻调用,谁先被调用是不确定的。    可选参数args将被传递给callback作为调用时的参数。如果你想给callback传递带名字的参数,把它们包起来或者用functools.partial()。

AbstractEventLoop.call_at(when, callback, *args)    安排callback在给定的时间戳when(int或者float)时调用;用AbstractEventLoop.time()作为参考。    这个方法的行为和AbstractEventLoop.call_later()一样。    返回值是asyncio.Handle的一个实例,用于中止这个callback。

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

1.4. Futures AbstractEventLoop.create_future()    创建一个关联到这个事件循环的asyncio.Future对象。    这是asyncio中创建Future的首选方式,作为事件循环的实现可以提供Future类的代替实现(有更好的性能或表现)。 新增于3.5.2版本。

1.5. 任务 AbstractEventLoop.create_task(coro)    安排一个协程对象的执行:把它包装在一个future里。返回一个任务(Task)对象。    第三方事件循环可以使用他们自己的Task子类来交互。在这种情况下,返回值类型是Task的子类。    这个方法是Python 3.4.2版本加入的。使用async()可以支持旧的Python版本。 新增于3.4.2版本。

AbstractEventLoop.set_task_factory(factory)    为AbstractEventLoop.create_task()设置一个task的工厂。    如果factory参数是None,将会设置为默认工厂。    如果factory参数是可被调用(callable)的,他应该可以接受(loop, coro)作为参数,loop是一个可用的事件循环,coro是协程对象。它必须返回一个asyncio.Future的兼容对象。 新增于3.4.4版本。

AbstractEventLoop.get_task_factory()    返回任务工厂,如果用的是默认的工厂,返回None。 新增于3.4.4版本。

1.6. 创建连接 coroutine AbstractEventLoop.create_connection(protocol_factory, host=None, port=None, *, ssl=None, family=0, proto=0, flags=0, sock=None, local_addr=None, server_hostname=None)    创建一个连接到给定的host(主机)和port(端口)的流传输连接:socket family是AF_INET还是AF_INET6取决于host(或者指定了family参数),socket type是SOCK_STREAM。protocol_factory必须是可被调用(callable)的且返回一个传输(protocol)实例。    这是一个协程方法,它将在后台默默地建立一个连接。建立成功的时候,返回一个(transport, protocol)元组((传输,协议)对)。

   按时间顺序的大概底层操作如下:

连接建立,创建一个传输(transport)来代表它。 protocol_factory被调用(没有参数),返回一个协议(protocol)实例。 这个协议(protocol)实例和传输(transport)捆绑在一起,其connection_made()方法被调用。 这个协程成功地返回(transport, protocol)对。    创建的传输是一个依赖于实现的双向流。

注意:protocol_factory可以是任意的可被调用(callable)对象,不一定要是一个类。例如,你想使用一个预先创建的协议实例,你可以写lambda: my_protocol。

   这些选项可以改变连接创建方式:

ssl:如果给了这个参数且不为false,将会创建一个SSL/TLS传输(默认是一个普通的TCP传输被创建)。如果ssl是一个ssl.SSLContext对象,这个上下文将被用于创建传输;如果ssl是True,一个带有一些未被指明的默认设置的上下文将被使用。(可以去参考官方文档ssl章节的SSL/TLS security considerations段落) server_hostname,只能和ssl参数一起使用,用于设置或覆盖将要匹配目标主机证书的主机名。默认会使用host参数。如果host参数为空,没有默认值,你必须填写server_hostname参数的值。如果server_hostname是一个空字符串,主机名匹配就被禁用了(这非常不安全,可能会产生中间人攻击)。 family,proto,flags是可选的地址族(address family)、协议(protocol)、位掩码(flags),来传给getaddrinfo()进行host参数的域名解析。如果给定这些参数,这些应该都是相应的socket模块的常量整数。 sock,如果给定这个参数,它必须是已存在的、已连接的socket.socket对象,来用于传输。如果给定了这个参数,host、port、family、proto、flags和local_addr参数都不应该给定。 local_addr,如果给定了这个参数,它应该是一个来用绑定到本地socket的(local_host, local_port)元组((本地地址,本地端口)元组)。local_host和local_port将使用getaddrinfo()来查询,类似于host和port参数。 改动于3.5版本:SSL/TLS现在支持Windows上的ProactorEventLoop了。

还可以看看open_connection()函数,它可以获得(StreamReader, StreamWriter)对,而不是一个协议。

coroutine AbstractEventLoop.create_datagram_endpoint(protocol_factory, local_addr=None, remote_addr=None, *, family=0, proto=0, flags=0, reuse_address=None, reuse_port=None, allow_broadcast=None, sock=None)    创建一个数据报连接:socket family是AF_INET还是AF_INET6取决于host(或者指定了family参数),socket type是SOCK_DGRAM。protocol_factory必须是可被调用(callable)的且返回一个传输(protocol)实例。    这是一个协程方法,它将在后台默默地建立一个连接。建立成功的时候,返回一个(transport, protocol)元组((传输,协议)对)。    这些选项可以改变连接创建方式:

local_addr,如果给定了这个参数,它应该是一个来用绑定到本地socket的(local_host, local_port)元组((本地地址,本地端口)元组)。local_host和local_port将使用getaddrinfo()来查询。 remote_addr,如果给定了这个参数,它应该是一个来用绑定到远程地址的socket的(remote_host, remote_port)元组((本地地址,本地端口)元组)。remote_host和remote_port将使用getaddrinfo()来查询。 family,proto,flags是可选的地址族(address family)、协议(protocol)、位掩码(flags),来传给getaddrinfo()进行host参数的域名解析。如果给定这些参数,这些应该都是相应的socket模块的常量整数。 reuse_address,这个参数告诉内核在TIME_WAIT状态下重用本地的socket,而不是等待它自然的超时过期。如果没有指定这个参数,在UNIX下默认设为True。 reuse_port,这个参数告诉内核允许这个端点绑定到这个端口,即使有另外的已存在的端点绑定了这个端口,只要它们在创建时也设置了这个参数就行。这个选项在Windows和部分UNIX上不被支持。如果SO_REUSEPORT这个常量没有被定义,那这个能力就是不支持的。 allow_broadcast,这个参数告诉内核允许这个端点发送消息给广播地址。 sock参数可以被指定来使用一个先前存在的、已连接的socket.socket对象来用于传输。如果指定了这个参数,local_addr和remote_addr必须被省略(必须为None)。    在Windows上的ProactorEventLoop循环里,这个方法还不被支持。    可以参考UDP客户端协议和UDP服务端协议实例。

coroutine AbstractEventLoop.create_unix_connection(protocol_factory, path, *, ssl=None, sock=None, server_hostname=None)    创建一个UNIX连接:socket family是AF_UNIX,socket type是SOCK_STREAM。AF_UNIX是用来进行同一机器上的不同进程间的高效通信的。    这是一个协程方法,它将在后台默默地建立一个连接。建立成功的时候,返回一个(transport, protocol)元组((传输,协议)对)。    参数可以参考AbstractEventLoop.create_connection()方法的参数。    仅适用于:UNIX。

1.7. 创建监听连接 coroutine AbstractEventLoop.create_server(protocol_factory, host=None, port=None, *, family=socket.AF_UNSPEC, flags=socket.AI_PASSIVE, sock=None, backlog=100, ssl=None, reuse_address=None, reuse_port=None)    创建一个TCP服务端(socket type是SOCK_STREAM),绑定到host和port参数(主机和端口)。    返回一个Server对象,它的sockets属性包含了已创建的socket。使用Server.close()方法来停止这个服务端:关闭监听的sockets。    参数:

host参数可以是一个字符串,在这种情况下TCP服务端绑定到host和port参数。host参数也可以是字符串序列,这种情况下TCP服务端绑定到host序列里的所有主机。如果host是空字符串或者None,所有的接口都被假定,返回一个有多个socket的list(最可能的用于IPv4的一个和IPv6的一个)。 family参数可以设置为socket.AF_INET或者AF_INET6来使socket强制使用IPv4或者IPv6。如果没有设置就会取决于host(默认是socket.AF_UNSPEC)。 flags是用于的getaddrinfo()的位掩码。 sock参数可以被指定,用来使用先前存在的socket对象。如果指定了,host和port参数应该被省略(必须为None)。 backlog参数是传递给listen()方法的最大等待连接数(默认为100)。 ssl参数可以设置一个SSLContext对象来在一个接受的连接上启用SSL。 reuse_address,这个参数告诉内核在TIME_WAIT状态下重用本地的socket,而不是等待它自然的超时过期。如果没有指定这个参数,在UNIX下默认设为True。 reuse_port,这个参数告诉内核允许这个端点绑定到这个端口,即使有另外的已存在的端点绑定了这个端口,只要它们在创建时也设置了这个参数就行。这个选项在Windows上不被支持。    这个是一个协程方法。

改动于3.5版本:SSL/TLS现在支持Windows上的ProactorEventLoop了。

还可以看看start_server()函数,它创建一个(StreamReader, StreamWriter)对,并且回调一个方法。

改动于3.5.1版本:host参数现在可以是一个字符串序列。

coroutine AbstractEventLoop.create_unix_server(protocol_factory, path=None, *, sock=None, backlog=100, ssl=None)    类似于AbstractEventLoop.create_server(),但是具体的socket family是AF_UNIX。    这个是一个协程方法。    仅适用于:UNIX。

1.8. 监视文件描述符(file descriptor) 对于Windows上的SelectorEventLoop,只有socket处理被支持(例如:管道文件描述符不被支持)。 对于Windows上的ProactorEventLoop,这些方法都不被支持。

AbstractEventLoop.add_reader(fd, callback, *args)    开始监视可读的文件描述符fd,然后会传递给定的args来调用callback。    (可以使用functools.partial()来给callback传递参数)

AbstractEventLoop.remove_reader(fd)    停止监视这个可读的文件描述符。

AbstractEventLoop.add_writer(fd, callback, *args)    开始监视可写的文件描述符fd,然后会传递给定的args来调用callback。    (可以使用functools.partial()来给callback传递参数)

AbstractEventLoop.remove_writer(fd)    停止监视这个可写的文件描述符。

最下面有这些方法的实例。

1.9. 低级socket操作 coroutine AbstractEventLoop.sock_recv(sock, nbytes)    从socket获取数据。仿照的socket.socket.recv()这个阻塞方法。    返回值是bytes(字节)对象,代表接受的数据。一次接受的字节数的最大值由nbytes参数指定。 SelectorEventLoop事件循环调用这个方法的时候,sock参数必须是非阻塞的socket。    这个是一个协程方法。

coroutine AbstractEventLoop.sock_sendall(sock, data)    给socket发送数据。仿照的socket.socket.sendall()这个阻塞方法。    这个socket必须连接一个远程的socket。这个方法持续的发送来自于data的数据,直到全部发送完毕或者有错误产生。成功时返回None。错误时会引发一个异常,并且此时没有办法确定多少数据(如果有的话)被成功地由该连接的接收端处理。 SelectorEventLoop事件循环调用这个方法的时候,sock参数必须是非阻塞的socket。    这个是一个协程方法。

coroutine AbstractEventLoop.sock_connect(sock, address)    连接到地址为address的远程socket上。仿照的socket.socket.connect()这个阻塞方法。 SelectorEventLoop事件循环调用这个方法的时候,sock参数必须是非阻塞的socket。    这个是一个协程方法。 改动于3.5.2版本:address参数不一定需要被解析。socket_connect会通过调用socket.inet_pton()来检查address是否被解析了。如果没有,AbstractEventLoop.getaddrinfo()将被用于解析这个address。

coroutine AbstractEventLoop.sock_accept(sock)    接受一个连接。仿照的socket.socket.accept()这个阻塞方法。    sock这个参数必须是已绑定到一个地址并且监听连接的socket。返回值是(conn, address)对,conn是一个新socket对象用于在连接上发送和接受数据,address是绑定到socket上的连接的另一端的地址。    sock参数必须是非阻塞的socket。    这个是一个协程方法。

1.10. 解析主机名 coroutine AbstractEventLoop.getaddrinfo(host, port, *, family=0, type=0, proto=0, flags=0)    这是一个协程方法,类似于socket.getaddrinfo(),但是不阻塞。

coroutine AbstractEventLoop.getnameinfo(sockaddr, flags=0)    这是一个协程方法,类似于socket.getnameinfo(),但是不阻塞。

1.11. 管道连接 Windows上的SelectorEventLoop不支持这些方法。Windows上的ProactorEventLoop支持这些方法。

coroutine AbstractEventLoop.connect_read_pipe(protocol_factory, pipe)    在事件循环里注册 读管道。    protocol_factory参数应该是带有Protocol接口的实例对象。pipe参数应该是一个类似文件(file-like)的对象。返回(transport, protocol)对,transport支持ReadTransport的接口。 SelectorEventLoop事件循环调用这个方法的时候,pipe必须是非阻塞模式。    这个是一个协程方法。

coroutine AbstractEventLoop.connect_write_pipe(protocol_factory, pipe)    在事件循环里注册 写管道。    protocol_factory参数应该是带有BaseProtocol接口的实例对象。pipe参数应该是一个类似文件(file-like)的对象。返回(transport, protocol)对,transport支持WriteTransport的接口。 SelectorEventLoop事件循环调用这个方法的时候,pipe必须是非阻塞模式。    这个是一个协程方法。

可以参考AbstractEventLoop.subprocess_exec()和AbstractEventLoop.subprocess_shell()方法。

1.12. UNIX信号 仅适用于:UNIX。

AbstractEventLoop.add_signal_handler(signum, callback, *args)    为信号添加一个处理程序。    如果信号的数值是无效的或者获取不了,会引发ValueError异常。如果设置处理程序时出现问题,会引发RuntimeError异常。    (可以使用functools.partial()来给callback传递参数)

AbstractEventLoop.remove_signal_handler(sig)    为信号移除处理程序。    如果信号处理程序被移除,返回True,否则返回False。

可以参考官方文档的signal模块。

1.13. 运行器(Executor) 在Executor(线程池或进程池)里调用函数。默认情况下,事件循环使用着一个线程池运行器(ThreadPoolExecutor)。

coroutine AbstractEventLoop.run_in_executor(executor, func, *args)    安排func在指定的运行器(executor)里调用。    executor参数应该是一个Executor实例。如果executor参数为None,就使用默认运行器。    (可以使用functools.partial()来给func传递参数)    这个是一个协程方法。

AbstractEventLoop.set_default_executor(executor)    为run_in_executor()函数设置默认运行器。

1.14. 错误处理API 让你定制事件循环里的异常处理。

AbstractEventLoop.set_exception_handler(handler)    把handler设置为新的事件循环的异常处理程序。    如果handler为None,就会设置为默认的异常处理程序。    如果handler是可被调用(callable)对象,他应该匹配(loop, context)作为参数,其中loop是一个活跃的事件循环,context是一个dict对象(具体参考下面的call_exception_handler()方法里的context)。

AbstractEventLoop.get_exception_handler()    返回异常处理程序,如果使用的是默认的那个就会返回None。 新增于3.5.2版本。

AbstractEventLoop.default_exception_handler(context)    默认的异常处理程序。    这个函数在异常发生且没有设置异常处理程序时被调用;也能被自己定制的异常处理程序调用,如果你想推迟默认行为的话。    context参数和下面的call_exception_handler()里的context意义一样。

AbstractEventLoop.call_exception_handler(context)    调用当前事件循环的异常处理程序。    context是一个包含以下关键字作为key的dict(一些新的key可能会在后面介绍):

'message': 错误消息; 'exception'(可选): 异常对象; 'future'(可选): asyncio.Future实例; 'handle'(可选): asyncio.Handle实例; 'protocol'(可选): Protocol(协议)实例; 'transport'(可选): Transport(传输)实例; 'socket'(可选): socket.socket实例。

注意:这个方法不应该被任何事件循环的子类重载。想使用自己定制的异常处理程序,请使用set_exception_handler()方法。 1.15. 调试模式 AbstractEventLoop.get_debug()    得到事件循环是否调试模式(布尔值)。    如果环境变量PYTHONASYNCIODEBUG被设置为一个非空的字符串,默认值是True;否则是False。 新增于3.4.2版本。

AbstractEventLoop.set_debug(enabled: bool)    为事件循环设置调试模式。 新增于3.4.2版本。

可以参考最后一章 使用asyncio开发 的 asyncio的调试模式 章节。

1.16. 服务端(Server) class asyncio.Server    监听socket的服务端。    通过AbstractEventLoop.create_server()方法和start_server()方法来创建对象;不要直接实例化这个类。 close()

      关闭服务:关闭监听的socket并且设置这些socket的属性为None。       那些代表现有的客户端连接的socket就悬空了。       服务端以同步方式关闭;使用wait_close()协程方法会等着服务端被关闭。 coroutinewait_close()

      等待close()方法完成。       这是一个协程方法。 sockets

      服务端正在监听的socket.socket对象的list;如果已经关闭了,会得到None。

1.17. Handle class asyncio.Handle    AbstractEventLoop.call_soon()、AbstractEventLoop.call_soon_threadsafe()、AbstractEventLoop.call_later()和AbstractEventLoop.call_at()的返回值,一个回调包装对象。 cancel()       关闭这个回调。如果这个回调已经关闭了或者已经运行了,这个方法无效。

1.18. 事件循环实例 1.18.1. 使用call_soon()的Hello World 使用call_soon()方法来安排一个回调的实例。这个回调函数显示“Hello World”然后停止事件循环。

import asyncio

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

loop = asyncio.get_event_loop()

安排调用hello_world()

loop.call_soon(hello_world, loop)

阻塞调用由loop.stop()中断

loop.run_forever() loop.close() 也可以查看使用协程的Hello World协程实例。

1.18.2. 使用call_later()显示当前时间 通过回调方式每秒钟显示当前时间的实例。在五秒钟之内,回调使用call_later()方法来安排它自己然后停止事件循环。

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

安排第一次调用display_date()

end_time = loop.time() + 5.0 loop.call_soon(display_date, end_time, loop)

阻塞调用由loop.stop()中断

loop.run_forever() loop.close() 也可以查看使用协程的显示当前时间协程实例。

1.18.3. 监视文件描述符的读取事件 使用add_reader()方法等待直到文件描述符获取了一些数据,然后停止事件循环。

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

创建一对连接的文件描述符

rsock, wsock = socketpair() loop = asyncio.get_event_loop()

def reader(): data = rsock.recv(100) print("Received:", data.decode()) # 我们完成了:注销文件描述符 loop.remove_reader(rsock) # 停止事件循环 loop.stop()

注册文件描述符的读事件

loop.add_reader(rsock, reader)

模拟来自网络的数据接收

loop.call_soon(wsock.send, 'abc'.encode())

运行事件循环

loop.run_forever()

我们完成了:关闭socket和事件循环

rsock.close() wsock.close() loop.close() 1.18.4. 为SIGINT和SIGTERM设置信号处理程序 使用add_signal_handler()方法为SIGINT和SIGTERM信号量注册处理程序。

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上。

转载于:https://www.cnblogs.com/c-x-a/p/9515839.html

相关资源:asyncio.pdf
最新回复(0)