Python的asyncio是使用 async/await 语法编写并发代码的标准库。经过上一节的讲解,咱们了解了它不断变化的发展历史。到了Python最新稳定版 3.7 这个版本,asyncio又作了比较大的调整,把这个库的API分为了 高层级API和低层级API,并引入asyncio.run()这样的高级方法,让编写异步程序更加简洁。shell
本节但愿提纲挈领地介绍最新 3.7 版的asnycio,先从全局认识Python这个异步IO库。编程
asyncio的高层级API主要提升以下几个方面:安全
asyncio的低层级API用以支持开发异步库和框架:网络
高层级API让咱们更方便的编写基于asyncio的应用程序。这些API包括:架构
协程经过 async/await 语法进行声明,是编写异步应用的推荐方式。历史的 @asyncio.coroutine
和 yield from
已经被弃用,并计划在Python 3.10中移除。协程能够经过 asyncio.run(coro, *, debug=False)
函数运行,该函数负责管理事件循环并完结异步生成器。它应该被用做asyncio程序的主入口点,至关于main函数,应该只被调用一次。并发
任务被用于并发调度协程,可用于网络爬虫的并发。使用 asyncio.create_task()
就能够把一个协程打包为一个任务,该协程会自动安排为很快运行。框架
协程,任务和Future都是可等待对象。其中,Future是低层级的可等待对象,表示一个异步操做的最终结果。异步
流是用于网络链接的高层级的使用 async/await的原语。流容许在不使用回调或低层级协议和传输的状况下发送和接收数据。异步读写TCP有客户端函数 asyncio.open_connection()
和 服务端函数 asyncio.start_server()
。它还支持 Unix Sockets: asyncio.open_unix_connection()
和 asyncio.start_unix_server()
。async
asyncio同步原语的设计相似于threading模块的原语,有两个重要的注意事项:
asyncio原语不是线程安全的,所以它们不该该用于OS线程同步(而是用threading)
这些同步原语的方法不接受超时参数; 使用asyncio.wait_for()
函数执行超时操做。
asyncio具备如下基本同步原语:分布式
asyncio提供了经过 async/await 建立和管理子进程的API。不一样于Python标准库的subprocess,asyncio的子进程函数都是异步的,而且提供了多种工具来处理这些函数,这就很容易并行执行和监视多个子进程。建立子进程的方法主要有两个:
coroutine asyncio.create_subprocess_exec()
coroutine asyncio.create_subprocess_shell()
asyncio 队列的设计相似于标准模块queue的类。虽然asyncio队列不是线程安全的,但它们被设计为专门用于 async/await 代码。须要注意的是,asyncio队列的方法没有超时参数,使用 asyncio.wait_for()
函数进行超时的队列操做。
由于和标注模块queue的类设计类似,使用起来跟queue无太多差别,只须要在对应的函数前面加 await 便可。asyncio 队列提供了三种不一样的队列:
asyncio提供了几种异常,它们是:
低层级API为编写基于asyncio的库和框架提供支持,有意编写异步库和框架的大牛们须要熟悉这些低层级API。主要包括:
事件循环是每一个asyncio应用程序的核心。 事件循环运行异步任务和回调,执行网络IO操做以及运行子进程。
应用程序开发人员一般应该使用高级asyncio函数,例如asyncio.run()
,而且不多须要引用循环对象或调用其方法。
Python 3.7 新增了 asyncio.get_running_loop()
函数。
Future对象用于将基于低层级回调的代码与高层级的 async/await 代码进行桥接。
Future表示异步操做的最终结果。 不是线程安全的。
Future是一个可等待对象。 协程能够等待Future对象,直到它们有结果或异常集,或者直到它们被取消。
一般,Futures用于启用基于低层级回调的代码(例如,在使用asyncio传输实现的协议中)以与高层级 async/await 代码进行互操做。
Transport 和 Protocol由低层级事件循环使用,好比函数loop.create_connection()
。它们使用基于回调的编程风格,并支持网络或IPC协议(如HTTP)的高性能实现。
在最高级别,传输涉及字节的传输方式,而协议肯定要传输哪些字节(在某种程度上什么时候传输)。
换种方式说就是:传输是套接字(或相似的I/O端点)的抽象,而协议是从传输的角度来看的应用程序的抽象。
另外一种观点是传输和协议接口共同定义了一个使用网络I/O和进程间I/O的抽象接口。
传输和协议对象之间始终存在1:1的关系:协议调用传输方法来发送数据,而传输调用协议方法来传递已接收的数据。
大多数面向链接的事件循环方法(例如loop.create_connection()
)一般接受protocol_factory参数,该参数用于为接受的链接建立Protocol对象,由Transport对象表示。 这些方法一般返回(传输,协议)元组。
事件循环策略是一个全局的按进程划分的对象,用于控制事件循环的管理。 每一个事件循环都有一个默认策略,可使用策略API对其进行更改和自定义。
策略定义了上下文的概念,并根据上下文管理单独的事件循环。 默认策略将上下文定义为当前线程。
经过使用自定义事件循环策略,能够自定义get_event_loop()
,set_event_loop()
和new_event_loop()
函数的行为。
asyncio模块设计为可移植的,但因为平台的底层架构和功能,某些平台存在细微的差别和限制。在Windows平台,有些是不支持的,好比 loop.create_unix_connection()
and loop.create_unix_server()
。而Linux和比较新的macOS所有支持。
Python 3.7 经过对asyncio分组使得它的架构更加清晰,普通写异步IO的应用程序只需熟悉高层级API,须要写异步IO的库和框架时才须要理解低层级的API。