python基础教程:异步IO 之 API

Python的asyncio是使用 async/await 语法编写并发代码的标准库。通过上一节的讲解,我们了解了它不断变化的发展历史。到了Python最新稳定版 3.7 这个版本,asyncio又做了比较大的调整,把这个库的API分为了 高层级API和低层级API,并引入asyncio.run()这样的高级方法,让编写异步程序更加简洁。

本节希望提纲挈领地介绍最新 3.7 版的asnycio,先从全局认识Python这个异步IO库。

asyncio的高层级API主要提高如下几个方面:

  • 并发地运行Python协程并完全控制其执行过程;
  • 执行网络IO和IPC;
  • 控制子进程;
  • 通过队列实现分布式任务;
  • 同步并发代码。

asyncio的低层级API用以支持开发异步库和框架:

  • 创建和管理事件循环(event loop),提供异步的API用于网络,运行子进程,处理操作系统信号等;
  • 通过transports实现高效率协议;
  • 通过async/await 语法桥架基于回调的库和代码。

asyncio高级API

高层级API让我们更方便的编写基于asyncio的应用程序。这些API包括:

(1)协程和任务

协程通过 async/await 语法进行声明,是编写异步应用的推荐方式。历史的 @asyncio.coroutineyield from 已经被弃用,并计划在Python 3.10中移除。协程可以通过 asyncio.run(coro, *, debug=False) 函数运行,该函数负责管理事件循环并完结异步生成器。它应该被用作asyncio程序的主入口点,相当于main函数,应该只被调用一次。

任务被用于并发调度协程,可用于网络爬虫的并发。使用 asyncio.create_task() 就可以把一个协程打包为一个任务,该协程会自动安排为很快运行。

协程,任务和Future都是可等待对象。其中,Future是低层级的可等待对象,表示一个异步操作的最终结果。

(2)流

流是用于网络连接的高层级的使用 async/await的原语。流允许在不使用回调或低层级协议和传输的情况下发送和接收数据。异步读写TCP有客户端函数 asyncio.open_connection() 和 服务端函数 asyncio.start_server() 。它还支持 Unix Sockets: asyncio.open_unix_connection()asyncio.start_unix_server()

(3)同步原语

asyncio同步原语的设计类似于threading模块的原语,有两个重要的注意事项: asyncio原语不是线程安全的,因此它们不应该用于OS线程同步(而是用threading) 这些同步原语的方法不接受超时参数; 使用asyncio.wait_for()函数执行超时操作。 asyncio具有以下基本同步原语:

  • Lock
  • Event
  • Condition
  • Semaphore
  • BoundedSemaphore

(4)子进程

asyncio提供了通过 async/await 创建和管理子进程的API。不同于Python标准库的subprocess,asyncio的子进程函数都是异步的,并且提供了多种工具来处理这些函数,这就很容易并行执行和监视多个子进程。创建子进程的方法主要有两个:

coroutine asyncio.create_subprocess_exec() coroutine asyncio.create_subprocess_shell()

(5)队列

asyncio 队列的设计类似于标准模块queue的类。虽然asyncio队列不是线程安全的,但它们被设计为专门用于 async/await 代码。需要注意的是,asyncio队列的方法没有超时参数,使用 asyncio.wait_for()函数进行超时的队列操作。 因为和标注模块queue的类设计相似,使用起来跟queue无太多差异,只需要在对应的函数前面加 await 即可。asyncio 队列提供了三种不同的队列:

  • class asyncio.Queue 先进先出队列
  • class asyncio.PriorityQueue 优先队列
  • class asyncio.LifoQueue 后进先出队列

(6)异常

asyncio提供了几种异常,它们是:

  • TimeoutError,
  • CancelledError,
  • InvalidStateError,
  • SendfileNotAvailableError
  • IncompleteReadError
  • LimitOverrunError

asyncio低级API

低层级API为编写基于asyncio的库和框架提供支持,有意编写异步库和框架的大牛们需要熟悉这些低层级API。主要包括:

(1)事件循环

事件循环是每个asyncio应用程序的核心。 事件循环运行异步任务和回调,执行网络IO操作以及运行子进程。

应用程序开发人员通常应该使用高级asyncio函数,例如asyncio.run(),并且很少需要引用循环对象或调用其方法。

Python 3.7 新增了 asyncio.get_running_loop()函数。

(2)Futures

Future对象用于将基于低层级回调的代码与高层级的 async/await 代码进行桥接。 Future表示异步操作的最终结果。 不是线程安全的。 Future是一个可等待对象。 协程可以等待Future对象,直到它们有结果或异常集,或者直到它们被取消。 通常,Futures用于启用基于低层级回调的代码(例如,在使用asyncio传输实现的协议中)以与高层级 async/await 代码进行互操作。

(3)传输和协议(Transports和Protocols)

Transport 和 Protocol由低层级事件循环使用,比如函数loop.create_connection()。它们使用基于回调的编程风格,并支持网络或IPC协议(如HTTP)的高性能实现。

在最高级别,传输涉及字节的传输方式,而协议确定要传输哪些字节(在某种程度上何时传输)。

换种方式说就是:传输是套接字(或类似的I/O端点)的抽象,而协议是从传输的角度来看的应用程序的抽象。

另一种观点是传输和协议接口共同定义了一个使用网络I/O和进程间I/O的抽象接口。

传输和协议对象之间始终存在1:1的关系:协议调用传输方法来发送数据,而传输调用协议方法来传递已接收的数据。

大多数面向连接的事件循环方法(例如loop.create_connection())通常接受protocol_factory参数,该参数用于为接受的连接创建Protocol对象,由Transport对象表示。 这些方法通常返回(传输,协议)元组。

(4)策略(Policy)

事件循环策略是一个全局的按进程划分的对象,用于控制事件循环的管理。 每个事件循环都有一个默认策略,可以使用策略API对其进行更改和自定义。

策略定义了上下文的概念,并根据上下文管理单独的事件循环。 默认策略将上下文定义为当前线程。

通过使用自定义事件循环策略,可以自定义get_event_loop()set_event_loop()new_event_loop()函数的行为。

(5)平台支持

asyncio模块设计为可移植的,但由于平台的底层架构和功能,某些平台存在细微的差异和限制。在Windows平台,有些是不支持的,比如 loop.create_unix_connection() and loop.create_unix_server()。而Linux和比较新的macOS全部支持。

总结

Python 3.7 通过对asyncio分组使得它的架构更加清晰,普通写异步IO的应用程序只需熟悉高层级API,需要写异步IO的库和框架时才需要理解低层级的API。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏诸葛青云的专栏

Python12306自动抢票下单,五一旅游回家就选Python!

X新闻者从中国铁路上海局集团有限公司获悉,五一的前8天(4月21日至28日)火车票已预售80万张。,东北、西南等多个方向尚有余票,铁路部门将采取动车组重联或增开...

29840
来自专栏linxu shell指南

yum简单修复指南

由于yum是强依赖于python,一旦pyhon环境改变(即默认的python bin程序路径改变),基本yum是跟着殉情的。

30730
来自专栏Python无止境

视频当道的时代,这些珍藏的优质 Python 播客值得推荐

我国互联网的发展道路与欧美不同,在内容的形式上,我们似乎实现了跨越式的发展——早早进入了移动互联网时代,直播和短视频等形式的内容成为了潮流,而文字形式的博客(b...

12030
来自专栏量子位

81个关键点,帮你紧密追踪女神的脸,比Dlib还多了13点 | 有代码

Niko说,他在Dlib库68个关键点的基础上加了13个,把前额也包含在追踪范围里。

14130
来自专栏Python无止境

如何在 Python 里面精确四舍五入?

花下猫语:如何精确地计算浮点数?这是计算机科学的大难题。那 Python 是如何处理浮点数的四舍五入问题的呢?今天分享的文章,对此展开了深入的剖析。

19520
来自专栏程序员的成长之路

实地探访:月薪 12K 的北京程序员是怎么工作生活的?

在当今社会,有网络的地方就有江湖,有江湖的地方就有程序员。我给大家在这里讲一个生活在北京的程序员,也就是生活中时常被提起的爱受伤的傻小子——白公子。

10050
来自专栏诸葛青云的专栏

Python入门必学,用Python练习画个美队盾牌

那问题来了,作为一个男人,怎么能忍?虽然是个明星,虽然是假的,虽然已经挽回不了败局了……那我就送个美队的盾牌给你吧……

24020
来自专栏量子位

Python官方中文文档上线了:各种教程已汉化,不用苦等野生翻译了

从今往后,不论是版本新变化,入门教程,语法讲解,Python模块安装指南……各种各样的手册,都可以直接看中文了。

50530
来自专栏量子位

Python之父称996惨无人道,系列项目霸榜GitHub,某宝商家开卖996文化衫

五天来,该项目已经获得12万程序员支持,拥有996.XXX系列至少4个衍生项目,持续霸占趋势榜第一名,Google可以搜到超过6万条结果。

9220
来自专栏量子位

李笑来登GitHub趋势榜第一,教你自学编程,含37%“硬核鸡汤”

这不,又一个项目,跃迁到了GitHub趋势榜的第一名,所以,今天量子位给大家介绍:

9840

扫码关注云+社区

领取腾讯云代金券

年度创作总结 领取年终奖励