深入Asyncio(三)Asyncio初体验
Asyncio初体验
Asyncio在Python中提供的API很复杂,其旨在替不同群体的人解决不同的问题,也正是由于这个原因,所以很难区分重点。
可以根据asyncio在Python中的特性,将其划分为两大主要群体:
1. 应用(最终用户)开发者,想要在应用开发中使用asyncio;
2. 框架开发者,制作框架或库以供应用开发者在他们的开发中使用。
在asyncio社区中大部分的问题基本都与这两个部分相关,例如,asyncio的官方文档更像是给框架开发者使用的,而非应用开发者,这导致应用开发者在阅读文档时很容易被其复杂性所震撼,给读者一种错觉就是在使用它之前,得看完全部的文档。
QuickStart
不需要关心官方文档的内容,要掌握asyncio库比想象中要容易。
PEP 492的作者、async Python的主要贡献者——Yury Selivanov——曾说过,asyncio的很多API都是给框架开发者提供的,应用开发人员需要掌握的只是所有API中的一小部分。
在本节我们将研究这些核心特性,并了解如何在Python中使用基于事件loop的编程,以此实现基本的异步。
要成为一个掌握asyncio的应用开发者,你需要知道的东西其实可以用一个小例子来展示。
import time
import asyncio
async def main():
print(f'{time.ctime()} Hello')
await asyncio.sleep(1.0)
print(f'{time.ctime()} Goodbye')
loop.stop() # 1
loop = asyncio.get_event_loop() # 2
loop.create_task(main()) # 3
loop.run_forever() # 4
pending = asyncio.Task.all_tasks(loop=loop)
group = asyncio.gather(*pending, return_exceptions=True) # 5
loop.run_until_complete(group) # 6
loop.close() # 7
λ python quickstart.py
Fri Sep 28 19:39:33 2018 Hello
Fri Sep 28 19:39:34 2018 Goodbye
- 通常用于信号控制,暂停循环,但循环可以重新启用不会消失;
- 在运行协程之前获得一个循环实例,只要是在单线程中,这个实例就是单例的;
- 只有调用这个方法,协程才能被执行,该调用返回的task对象可以用于获取任务状态、结果,或可通过task.cancel()取消任务;
- 实现循环运行的方法之一,会阻塞当前线程(通常是主线程);
- 通常习惯是在程序入口处执行
loop.run_forever()
方法,在收到停止信号时停止循环,然后收集那些还未完成的task,调用loop.run_until_complete()
方法等待其执行完毕,但更多的是用这个方法收集协程任务并取消它们,然后等待其执行完毕; - 实现循环运行的方法之一,同样阻塞当前线程,其保持循环运行直到其上调度的协程完成;
- 通常在最后调用,必须在调用
loop.stop()
方法的基础上使用,会导致循环永久消失。
上述例子漏了一些东西,其中最重要的是如何运行阻塞函数,我们知道协程就是函数中使用了await
关键字进行切换,但在当前async def
还没获得广泛支持前,使用阻塞函数/库是不可避免的。
为此,asyncio提供了一个与concurrent.futures
包中的API类似的API,它提供了ThreadPoolExecutor
和ProcessPoolExecutor
,默认基于线程,但很容易用基于进程的替换,这里面有些特殊的地方要注意。
import time
import asyncio
async def main():
print(f'{time.ctime()} Hello')
await asyncio.sleep(1.0)
print(f'{time.ctime()} Goodbye')
loop.stop()
def blocking(): # 1
time.sleep(0.5) # 2
print(f'{time.ctime()} Hello from a thread!')
loop = asyncio.get_event_loop()
loop.create_task(main())
loop.run_in_executor(None, blocking) # 3
loop.run_forever()
pending = asyncio.Task.all_tasks(loop=loop) # 4
group = asyncio.gather(*pending)
loop.run_until_complete(group)
loop.close()
λ python quickstart_exe.py
Fri Sep 28 20:21:21 2018 Hello
Fri Sep 28 20:21:22 2018 Hello from a thread!
Fri Sep 28 20:21:22 2018 Goodbye
- 这个函数调用了常规的sleep(),这会阻塞主线程并阻止loop运行,我们不能使这个函数变成协程,更糟糕的是不能在主线程运行loop时调用它,解决办法是用一个executor来运行它;
- 注意一点,这个sleep运行时间比协程中的sleep运行时间要短,后文再讨论如果长的话会发生什么;
- 该方法帮助我们在事件loop里用额外的线程或进程执行函数,这个方法的返回值是一个Future对象,意味着可以用await来切换它;
- 挂起的task中不包含前面的阻塞函数,并且这个方法只返回task对象,绝对不会返回Future对象。
好了,通过上面的学习,已经掌握了应用开发者对于asyncio库需要的最重要的部分,接下来将拓展知识并对API进行层次理解,这会让你更容易理解如何从文档中获取信息。
Asyncio全览
从前面一节发现,应用开发者只需几个命令就可以使用asyncio,但不幸的是官方文档巨量的API和扁平化的显示格式,让人很难分清哪些命令更通用,哪些命令是向框架开发者提供的,框架开发者可以通过文档寻找钩子并连接到其框架中,接下来我们从框架开发者的角度来看他们如何构建新的异步兼容库。
Level | Concept | Implementation |
---|---|---|
9 | Network: streams | StreamReader & StreamWriter |
8 | Network: TCP & UDP | Protocol |
7 | Network: transports | BaseTransport |
6 | tools | asyncio.Queue |
5 | subprocesses & threads | run_in_executor(), asyncio.subprocess |
4 | tasks | asyncio.Task |
3 | futures | asyncio.Future |
2 | event loop | BaseEventLoop |
1 | coroutines | async def & await |
上表中加粗字体对于应用开发者最重要,级别分为9级,1级最基础。
- 一级,设计第三方框架的最低级别,但在流行的
Curio
和Trio
中并不常用,它们只依赖于Python中的本地协程,不依赖asyncio库模块; - 二级,事件loop被分离出来,因此可以对其进行替换,比如
uvloop
实现了比标准库更快的循环; - 三四级,带来了Future和Task对象,Task是Future的子类,可将它们简单地视作同一个等级,Future对象表示某种正在进行的动作,其将通过事件循环的notification返回结果,而Task对象表示运行在事件循环上的协程,简单理解为Future是“循环感知”的,Task是“循环感知”+“异步感知”的,应用开发更多地使用Task,框架开发者的使用比例要看代码细节;
- 五级,有关启动方面工具,并等待运行在单独的线程或进程上的工作;
- 六级,附加的异步通信工具,比如
asyncio.Queue
,提供与Queue
模块类似的API,但原版的get和put方法会阻塞线程,因此这里提供的队列通过增加wait
关键字以支持异步; - 七到九级,网络IO层级,对应用开发者来说Stream十分方便,Protocol提供比Stream更细粒度的API,所有能使用Stream的地方都能用Protocol代替,除非要创建一个定制传输协议的框架供他人使用,否则几乎用不到Transport。
小结
在QuickStart中,掌握了快速上手的几个API;现在,对整个asyncio有了清晰的层级划分。这里再对上述知识进行强调:
- 第一级,知道如何写async def函数,如何使用await关键字来调用执行其它协程;
- 第二级,知道如何进行事件loop开关、交互;
- 第五级,知道如何在事件loop中运行阻塞程序,因为大多数第三方库都不支持异步,比如ORM库;
- 第六级,协程间数据通信使用asyncio.Queue等;
- 第九级,Streams的API提供了最简单的方式来使用socket进行网络通信。
如果使用提供异步兼容的第三方库,如aiohttp
,那么就不用直接使用asyncio的网络层,但这会导致对第三方库的依赖。
随着Python的发展,asyncio库以后可能会提供更多的API,现在也只是大致地分了几个层级。
深入Asyncio(三)Asyncio初体验的更多相关文章
- 第三次随笔--安装虚拟机及学习linux系统初体验
第三次随笔--安装虚拟机及学习linux系统初体验 ·学习基于VirtualBox虚拟机安装Ubuntu图文教程在自己笔记本上安装Linux操作系统 首先按照老师的提示步骤进行VirtualBox虚拟 ...
- 20155315庄艺霖第三次作业之Linux初体验
Linux初体验 安装Linux三两事 老师的作业要求基于VirtualBox安装Linux系统,我一开始下载了VB但是电脑运行不了,后来看网上的教程下载了VMware,才算开始了我的Linux之旅. ...
- git初体验(三)git分支
分支的理念就是分身,就像孙悟空拔出猴毛变出很多跟自己一模一样的猴子,然后每个猴子做自己的事情互不干涉,等到所有猴子做完之后,猴子集合来合并劳动成果,然后悟空就把那些猴子猴孙门统统收回了. 你创建了一个 ...
- Linux内核驱动学习(三)字符型设备驱动之初体验
Linux字符型设备驱动之初体验 文章目录 Linux字符型设备驱动之初体验 前言 框架 字符型设备 程序实现 cdev kobj owner file_operations dev_t 设备注册过程 ...
- Spring(三) Spring IOC 初体验
Web IOC 容器初体验 我们还是从大家最熟悉的 DispatcherServlet 开始,我们最先想到的还是 DispatcherServlet 的 init() 方法.我们发现在 Dispath ...
- Python 3.8.0 正式版发布,新特性初体验 全面介绍
Python 3.8.0 正式版发布,新特性初体验 北京时间 10 月 15 日,Python 官方发布了 3.8.0 正式版,该版本较 3.7 版本再次带来了多个非常实用的新特性. 赋值表达式 PE ...
- Xamarin.iOS开发初体验
aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAAAKwAAAA+CAIAAAA5/WfHAAAJrklEQVR4nO2c/VdTRxrH+wfdU84pW0
- 在同一个硬盘上安装多个 Linux 发行版及 Fedora 21 、Fedora 22 初体验
在同一个硬盘上安装多个 Linux 发行版 以前对多个 Linux 发行版的折腾主要是在虚拟机上完成.我的桌面电脑性能比较强大,玩玩虚拟机没啥问题,但是笔记本电脑就不行了.要在我的笔记本电脑上折腾多个 ...
- 百度EChart3初体验
由于项目需要在首页搞一个订单数量的走势图,经过多方查找,体验,感觉ECharts不错,封装的很细,我们只需要看自己需要那种类型的图表,搞定好自己的json数据就OK.至于说如何体现出来,官网的教程很详 ...
随机推荐
- 【asp.net】Win7旗舰版IIS配置
1.IIS配置流程 win7 iis 的配置不需要插入安装盘,可直接在控制面板中开启该功能,步骤如下: (1)"控制面板"-->"程序和功能"--> ...
- 《Linux命令行与shell脚本编程大全 第3版》Linux命令行---16
以下为阅读<Linux命令行与shell脚本编程大全 第3版>的读书笔记,为了方便记录,特地与书的内容保持同步,特意做成一节一次随笔,特记录如下:
- Caps_Locl exchang Esc
vim ~/.Xmodmap 1 remove Lock = Caps_Lock 2 keysym Escape = ...
- HashMap和TreeMap的常用排序方法
一.简单描述 Map是键值对的集合接口,它的实现类主要包括:HashMap,TreeMap,HashTable以及LinkedHashMap等. TreeMap:能够把它保存的记录根据键(key)排序 ...
- phpexcel--导入excel表格
最近在做一个小项目,就是一个管理信息的小系统:要求有导入和导出的信息为excel的功能,研究过导入导出功能的肯定知道导出要比导入的简单多了,导入用的phpexcel,当时对phpexcel是完全不了解 ...
- 【剑指offer】数组中重复的数字
题目描述 在一个长度为n的数组里的所有数字都在0到n-1的范围内. 数组中某些数字是重复的,但不知道有几个数字是重复的.也不知道每个数字重复几次.请找出数组中任意一个重复的数字. 例如,如果输入长度为 ...
- poj 1185 炮兵阵地 [经典状态压缩DP]
题意:略. 思路:由于每个大炮射程为2,所以如果对每一行状态压缩的话,能对它造成影响的就是上面的两行. 这里用dp[row][state1][state2]表示第row行状态为state2,第row- ...
- 2016集训测试赛(二十一)Problem C: 虫子
题目大意 给你一棵树, 每个点有一个点权. 有两种操作: link / cut 修改某个点的点权 每次操作后, 你要输出以下答案: 在整棵树中任意选两个点, 这两个点的LCA的期望权值. Soluti ...
- Cygwin下vi和vim方向键和Backspace不好用的问题(转)
执行p4 client时vi打开文本,编辑起来恼火,于是找到了这个: 默认的vi(vim)没有配置文件,因此导致了方向键出现ABCD,以及Backspace只会移动光标,字符不消失的问题.cygwin ...
- 开篇有益:为什么选择MongoDB?
为啥用MongoDB? 赶NoSQL时髦? Auto-shard等激动人心的特性? •No! 08年,还都是浮云. 最初的想法是寻找一个可靠的分布式K/V解决MySQL的问题. NoSQL(NoSQL ...