# Python asyncio 文档的翻译(待续)

原创
2018/03/01 22:50
阅读数 406

Python asyncio

asyncio中简单概念

  • event_loop 事件循环:程序开启一个无限的循环,程序员会把一些函数注册到事件循环上。当满足事件发生的时候,调用相应的协程函数。
  • coroutine 协程:协程对象,指一个使用async关键字定义的函数,它的调用不会立即执行函数,而是会返回一个协程对象。协程对象需要注册到事件循环,由事件循环调用。
  • task 任务:一个协程对象就是一个原生可以挂起的函数,任务则是对协程进一步封装,其中包含任务的各种状态。
  • future: 代表将来执行或没有执行的任务的结果。它和task上没有本质的区别
  • async/await 关键字:python3.5 用于定义协程的关键字,async定义一个协程,await用于挂起阻塞的异步调用接口。

来之:http://python.jobbole.com/87310/

BaseEventLoop

EventLoop是asyncio用来执行协程任务等类,它主要的作用有:

  • 注册,执行、取消函数(task)。
  • 创建用于通信的不同Transports的客户端和服务端。
  • 创建子进程和用于与其他进程通信的Transports。
  • 将执行代价高的函数委托给线程池。
asyncio.BaseEventLoop

BaseEventLoopAbstractEventLoop的子类,并实现了内部功能,但它不可以被直接继承,因为BaseEventLoop的内部接口并不稳定。

asyncio.AbstractEventLoop

AbstractEventLoop是event loop的虚类,自定义event loop则应该继承AbstractEventLoop, 注意这个类是线程不安全的

运行event loop

AbstractEventLoop.run_forever()

一直阻塞执行,知道stop()被调用。如果stop()run_forever()之前被调用,则会在无阻塞(?超时为0)的情况下轮询一遍内部的I/O选择器,运行响应I/O事件(以及已调度的那些事件)的所有回调,然后退出。如果在run_forever()执行中时调用stop(),则将在执行完当前批次的回调后退出。在这个情况下,所有的回调将不会继续执行,直至下次继续调用run_forever()

AbstractEventLoop.run_until_complete(future)

执行,直到future完成。

coroutine对象必须由ensure_future()包装后才能作为参数。

函数将会返回future的结果,或者抛出异常。

AbstractEventLoop.is_running()

返回event loop是否正在运行

AbstractEventLoop.stop()

停止event loop的运行

AbstractEventLoop.is_closed()

如果event loop已经关闭,返回True

AbstractEventLoop.close()

关闭 event loop 。 event loop 不能在running的状态(所以应该先stop再close)。处于Pending状态的回调将会丢失。

这个操作将会清除内部的队列和关闭内部执行器,而且不会等待执行器完成。

这个方法是幂等且不可逆的。close()之后不应该继续调用其他方法。

coroutine AbstractEventLoop.shutdown_asyncgens()

Python 3.6中新增

使用aclose()去关闭所有当前打开的*异步生成器(asynchronous generator)*对象。调用这个shutdown_asyncgens()之后,只要重新生成新的异步生成器,event loop 就会发出警告(issue)。这个方法应该用来让所有预定的异步生成器可靠地完成。

try:
	loop.run_forever()
finally:
	loop.run_until_complete(loop.shutdown_asyncgens())
	loop.close()

Calls(方法调用)

大部分asyncio中接收函数作为参数的方法,都不支持设置函数参的键值参数。如果需要对回调或者这些函数参设置键值参数,请使用functools.partial()。例如loop.call_soon(functools.partial(print, "hello", flush=True))这相当于print("Hello", flush=True)

注意

使用functools.partial()会比使用lambda表达式更好,因为asyncio在debug模式下,可以显示functools.partial()对象的参数,相对来说lambda表达式在debug模式下少很多信息。

AbstractEventLoop.call_soon(callback, *args)

会尽快的调用参数中的callbackcallback将会在call_soon返回后调用。

这个操作是FIFO(先进先出)的,callback将会按照注册的顺序调用,每个callback只会调用一次。

在调用时,参数callback后的*args将会依次的解析到callback中。

这个函数将会返回一个asyncio.Handle的对象,可以用这个对象来取消调用。

AbstractEventLoop.call_soon_threadsafe(callback, *args)

call_soon类似,只是该方法线程安全。

Delayed calls(延时调用)

event loop拥有自己内部实现的时钟信号。这个时钟信号时依赖于(系统平台)event loop的内部实现。理想情况下,这是一个单调的时钟(monotonic clock)。这通常是与time.time()不兼容的。

注意

超时和设置时间(设置什么时候调用的时间)与当前时间差不能超过1天

AbstractEventLoop.call_later(delay, callback, *args)

在超过设置的delay(int或者float)秒后,调用callback

这个函数将会返回一个asyncio.Handle的对象,可以用这个对象来取消调用。

同一个callback可以多次调用call_later()。如果2个callback被设置为同一时间调用,是无法确定它们的确切调用顺序的。

在调用时,参数callback后的*args将会依次的解析到callback中。

AbstractEventLoop.call_at(when, callback, *args)

在给定时间戳when(int或者float),调用callback。要使用 AbstractEventLoop.time()相关联的时间戳。

这个函数的行为与call_later()类似。

这个函数将会返回一个asyncio.Handle的对象,可以用这个对象来取消调用。

AbstractEventLoop.time()

返回当前时间,返回值是一个float的时间戳。时间戳基于 event loop 的内部时钟。

Futures

AbstractEventLoop.create_future()

创建并返回一个绑定在这个 event loop的asyncio.Future对象。

这是在asyncio中创建future的推荐方式,这是因为根据 event loop 的实现,event loop 可以提供一个替代的Future类(具有更好的性能或更多的方法)。

Tasks

AbstractEventLoop.create_task(coro)

安排coroutine对象执行:用一个future对象将coro封装。这个方法返回一个Task对象。

第三方 event loop 可以使用他们自己的Task子类来实现更多的操作。 在这种情况下,结果类型是Task的一个子类。

AbstractEventLoop.set_task_factory(factory)

设置一个工厂方法给AbstractEventLoop.create_task()使用。

如果factory是None,将会使用默认的工厂方法生成task

如果factory是一个可调用对象,它必须使用(loop, coro)作为参数,loop将会关联到一个active的 event loop,coro为一个coroutine(协程)对象。这个可调用对象,必须要返回一个与asyncio.Future兼容的对象。

AbstractEventLoop.get_task_factory()

返回正在使用的task工厂方法,如果返回的是None,则使用的是默认的工厂方法。

Creating connections(创建连接)

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)

*这是一个coroutine(协程)方法

根据给定的hostport创建一个连接到Internent的流式连接。socket family AF_INETAF_INET6取决于主机(或指定的family),socket typeSOCK_STREAM。参数protocol_factory必须是一个返回protocol对象的 callable(可调用对象)。

这个协程方法,将会在后台建立连接。当成功时,这个协程将会返回一对(transport, protocol)

这个方法基本的流程如下:

  1. 连接已经建立,并创建了一个transport来代表它。
  2. protocol_factory不需要任何参数就可以被调用,并返回一个protocol实例。
  3. 这个protocol实例将会与transport绑定,并调用protocol实例的connection_made()方法。
  4. 这个协程方法成功返回一对(transport, protocol)

这个创建成功的transport是一个双向流。

注意

protocol_factory可以是任何类型的可调用对象,不一定是一个类。例如,如果想使用一个已经创建好的protocol实例,可以使用如下的lambda表达式:lambda: my_protocol

可选参数:

  • ssl: 如果给定一个非false的参数,将会创建一个 SSL/TLS transport(默认情况下是一个TCP连接)。如果给定的ssl是一个ssl.SSLContext对象,这个context(上下文)将会被用来创建连接。如果sslTrue,将会使用一个未指定默认设置的context(上下文)来创建连接。
  • server_hostname: 这个一个与ssl配合使用的参数,用来设置或者覆盖与目标服务器的证书匹配的主机名。默认情况下,会使用host的值。如果host为空,将会没有默认值,所以必须给server_hostname设值。如果server_hostname是一个空字符(‘’),那么主机名匹配将会被禁用(这是一个严重的安全问题,会引起中间人攻击)。
  • family, proto, flags都是可选的 address family,protocol 和 flags,它们通过getaddrinfo()来给host解析。如果设置这些值,它们必须是来之socket模块的对应常量。
  • sock,这个值是指定一个已经连接的socket.socket对象来给transport使用。如果给定了sock,则不应该指定hostportfamilyprotoflagslocal_addr
  • local_addr,这是一个local_host, local_port的二元组,用于绑定本地的socket。乐意使用 getaddrinfo() 来查找local_hostlocal_port,与hostport类似。

另外

open_connection()方法可以用来获取一对(StreamReader, StreamWriter),而不是一个protocol

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)

*这是一个coroutine(协程)方法

创建一个的数据报连接。socket family AF_INETAF_INET6取决于主机(或指定的family),socket typeSOCK_DGRAM。参数protocol_factory必须是一个返回protocol对象的 callable(可调用对象)。

这个协程方法,将会在后台建立连接。当成功时,这个协程将会返回一对(transport, protocol)

可选参数:

  • local_addr,这是一个(local_host, local_port)的二元组,用于绑定本地的socket。使用 getaddrinfo() 来查找local_hostlocal_port,与hostport类似。
  • remote_addr,这是一个(remote_host, remote_port)的二元组,用于将socket连接到一个远程地址。可以使用 getaddrinfo() 来查找remote_hostremote_port
  • family, proto, flags都是可选的 address family,protocol 和 flags,它们通过getaddrinfo()来给host解析。如果设置这些值,它们必须是来之socket模块的对应常量。
  • reuse_address告诉系统内核复用一个处于 TIME_WAIT 状态的 socket ,而不用等待超时时间。如果没有特殊指定,在UNIX中,这个参数会自动设置为True
  • reuse_port告诉内核允许此端点(endpoint)与其他现有的端点(endpoint)绑定到相同的端口,只要这些端点(endpoint)在创建时都设置了此标志即可。Window和部分UNIX不支持此选项。如果没有系统中定义SO_REUSEPORT常量,则不支持此功能。
  • allow_broadcast告诉系统内核允许这些端点(endpoint)发送消息到一个广播地址。
  • sock 提供一个已经存在和连接的socket.socket对象。如果提供了socklocal_addrremote_addr都必须为None

在Window上的ProactorEventLoop,不支持这个方法。

AbstractEventLoop.create_unix_connection(protocol_factory, path, *, ssl=None, sock=None, server_hostname=None)

*这是一个coroutine(协程)方法

创建一个 UNIX 连接:socket family 为 AF_UNIX,socket type 为 SOCK_STREAMAF_UNIX是用来在同一台机器上不同的进程间进行高效通信的。

这个协程方法,将会在后台建立连接。当成功时,这个协程将会返回一对(transport, protocol)

path是是UNIX域socket的名称,除非指定了socket的参数,否则path是必须的。Abstract UNIX sockets,str 和 bytes 的path都是支持的。

Creating listening connections(创建服务端的监听连接)

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)

*这是一个coroutine(协程)方法

创建一个绑定在hostport的TCP Server(socket type 为 SOCK_STREAM)。

返回一个Server对象,这个对象里面的sockets属性包含已经创建好的 sockets 。想要停止server(关闭监听连接的socket),要使用Server.close()方法。

参数:

  • host:当host是一个字符串的时候,TCP Server 将会绑定在hostport上。当然,host参数也可以是多个字符串,在这种情况下,TCP Server 将会绑定在参数提供的所有host上。如果host是一个空字符串或者None,则会默认假定是使用所有接口,并返回多个sockets(最大的可能是返回一个 IPV4 的和一个 IPV6 的)。
  • family:可以是socket.AF_INET或者socket.AF_INET6,对应着 IPV4 和 IPV6。如果没有设置,这会取决于主机(默认为socket.AF_INSPEC)。
  • flag:是一个来自getaddrinfo()的掩码。
  • sock:一个可选参数,用来指定使用一个已经存在的 socket 。如果指定了,则应该省略hostport(必须为None)。
  • backlog:是传递给listen()的最大连接数(默认值为100)。
  • ssl:可以设置一个SSLContext来使用SSL连接。
  • reuse_address:将会告诉系统内核,可以复用一个正处于TIME_WAIT状态的本地 socket ,而不需要等待它超时。如果没有指定,在 UNIX 上将会自动的设为True
  • reuse_port:告诉系统内核允许此端点(endpoint)绑定到与其他现有的端点(endpoint)相同的端口,只要它们都设置了此标记即可。Window上不支持此选项。

在Python 3.5中,Window上的ProactorEventLoop已经支持SSL/TLS。

AbstractEventLoop.create_unix_server(protocol_factory, path=None, *, sock=None, backlog=100, ssl=None)

*这是一个coroutine(协程)方法

类似于方法AbstractEventLoop.create_server,不同的是 socket family 使用的是AF_UNIX

BaseEventLoop.connect_accepted_socket(protocol_factory, sock, *, ssl=None)

*这是一个coroutine(协程)方法

处理接收的连接。

这是用在Server端,使其能够接受来之asyncio之外的连接,并使用asyncio来处理它们。

参数:

  • sock:一个返回自accept方法的,已经存在的 socket 对象。
  • ssl:可以设置一个SSLContext来启用SSL处理连接。

这个协程函数,完成后将会返回一对(transport, protocol)

Watch file descriptors(监控文件描述符)

在Window上的SelectorEventLoop上,只支持 socket handle (不支持管道(pipe)文件描述符)。

在Window上的ProactorEventLoop上,都不支持这些方法。

AbstractEventLoop.add_reader(fd, callback, *args)

开始监控文件描述符,当文件描述符处于可读状态时,使用指定的参数调用回调函数callback

AbstractEventLoop.remove_reader(fd)

停止监控文件描述符的可读状态。

AbstractEventLoop.add_writer(fd, callback, *args)

开始监控文件描述符,当文件描述符处于可写状态时,使用指定的参数调用回调函数callback

AbstractEventLoop.remove_writer(fd)

停止监控文件描述符的可写状态。

18.5.1.9. Low-level socket operations

AbstractEventLoop.sock_recv(sock, nbytes)

*这是一个coroutine(协程)方法

从 socket 中接收数据。在socket.socket.recv()方法阻塞后建模(Modeled?)。

返回值是接收到的二进制(bytes)对象。一次接收的最大数据量由参数nbytes指定。

当使用SelectorEventLoop这个 event loop时,socket 对象 sock 必须是无阻塞(non-blocking)模式。

AbstractEventLoop.sock_sendall(sock, data)

*这是一个coroutine(协程)方法

将数据发送给 socket 。在socket.socket.sendall()方法阻塞后建模(Modeled?)。

这个 socket 对象必须已经连接到了一个远程的socket。这个方法将会一直发送data中的数据,直至到所有的数据发送完毕或者有错误发生。如果函数返回None表示成功。当发生错误时,将会抛出一个 exception,也无法确定接收端成功处理了多少的数据或者是否接收到数据。

当使用SelectorEventLoop这个 event loop时,socket 对象 sock 必须是无阻塞(non-blocking)模式。

AbstractEventLoop.sock_connect(sock, address)

*这是一个coroutine(协程)方法

连接到address的远程 socket。在socket.socket.connect()方法阻塞后建模(Modeled?)。

当使用SelectorEventLoop这个 event loop时,socket 对象 sock 必须是无阻塞(non-blocking)模式。

在Python 3.5.2中的改动:address不再需要已经被解析了。sock_connect将会调用socket.inet_pton()来检查地址是否已经被解析。如果没有,则将会调用AbstractEventLoop.getaddrinfo()去解析地址。

参照

AbstractEventLoop.create_connection()asyncio.open_connection()

AbstractEventLoop.sock_accept(sock)

*这是一个coroutine(协程)方法

接收一个连接。在socket.socket.accept()方法阻塞后建模(Modeled?)。

参数的 socket 必须已经绑定到一个地址上而且正在监听着连接。函数返回的值是一对(conn, address)。其中conn是一个新的 socket 对象,这个 socket 是用来在这个连接上接收和发送数据的。address是绑定到连接另一端的socket的地址。

这个 socket sock必须是无阻塞(non-blocking)的。(?)

参照

AbstractEventLoop.create_server()asyncio.start_server()

Resolve host name

AbstractEventLoop.getaddrinfo(host, port, *, family=0, type=0, proto=0, flags=0)

*这是一个coroutine(协程)方法

类似于socket.getaddrinfo(),但本方法是非阻塞(non-blocking)的。

AbstractEventLoop.getnameinfo(sockaddr, flags=0)

*这是一个coroutine(协程)方法

类似于socket.getnameinfo()方法,但本方法是非阻塞(non-blocking)的。

Connect pipes

在Window上,SelectorEventLoop是不支持以下方法的,若要使用,请用ProactorEventLoop

AbstractEventLoop.connect_read_pipe(protocol_factory, pipe)

*这是一个coroutine(协程)方法

在 event loop 中注册一个读管道(read pipe)。

protocol_factory应该使用Protocol接口来实例化对象。

管道是一个类似与文件(file)的对象。

这个函数将返回一对(transport, protocol),其中transport会支持ReadTransport这个接口。

当使用SelectorEventLoop时,这个pipe是被设置为非阻塞(non-blocking)模式。

AbstractEventLoop.connect_write_pipe(protocol_factory, pipe)

*这是一个coroutine(协程)方法

protocol_factory应该使用BaseProtocol接口来实例化对象。

管道是一个类似与文件(file)的对象。

这个函数将返回一对(transport, protocol),其中transport会支持WriteTransport这个接口。

当使用SelectorEventLoop时,这个pipe是被设置为非阻塞(non-blocking)模式。

UNIX signals

只适用于UNIX系统。

AbstractEventLoop.add_signal_handler(signum, callback, *args)

为指定的信号添加处理函数。

如果指定的信号无效或者是无法捕获的,则会引起ValueError。如果在设置callback的时候出现问题,则会引起RuntimeError

AbstractEventLoop.remove_signal_handler(sig)

移除指定信号的处理函数。

如果处理函数成功移除,则返回True,否则返回False

Executor

在 Executor(线程池或者进程池) 中调用函数。默认情况下,event loop 会使用一个线程池的 executor(ThreadPoolExecutor)。

AbstractEventLoop.run_in_executor(executor, func, *args)

*这是一个coroutine(协程)方法

设置func在指定的executor中调用。

参数executor必须是一个Executor对象。如果参数executor设置为None,将会使用默认的 executor 。

这个函数在Python 3.5.3中有改动:BaseEventLoop.run_in_executor()不再需要配置它创建的线程池的max_workers,而是将这个值的默认值留到线程池执行器(ThreadPoolExecutor)中设置。

AbstractEventLoop.set_default_executor(executor)

run_in_executor()设置一个默认的executor

展开阅读全文
打赏
0
1 收藏
分享
加载中
更多评论
打赏
0 评论
1 收藏
0
分享
返回顶部
顶部