异步IO:async/await
async/await
用asyncio
提供的@asyncio.coroutine
可以把一个generator标记为coroutine类型,然后在coroutine内部用yield from
调用另一个coroutine实现异步操作。
为了简化并更好地标识异步IO,从Python 3.5开始引入了新的语法async
和await
,可以让coroutine的代码更简洁易读。
请注意,async
和await
是针对coroutine的新语法,要使用新的语法,只需要做两步简单的替换:
- 把
@asyncio.coroutine
替换为async
; - 把
yield from
替换为await
。
让我们对比一下上一节的代码:
1 2 3 4 5 | @asyncio .coroutine def hello(): print ( "Hello world!" ) r = yield from asyncio.sleep( 1 ) print ( "Hello again!" ) |
用新语法重新编写如下:
1 2 3 4 | async def hello(): print ( "Hello world!" ) r = await asyncio.sleep( 1 ) print ( "Hello again!" ) |
剩下的代码保持不变。
小结:
Python从3.5版本开始为asyncio
提供了async
和await
的新语法;
注意新语法只能用在Python 3.5以及后续版本,如果使用3.4版本,则仍需使用上一节的方案。
练习
将上一节的异步获取sina、sohu和163的网站首页源码用新语法重写并运行。
async_hello2.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | import asyncio import threading import time async def hello(): print ( 'Hello world! %s' % threading.currentThread() ) await asyncio.sleep( 1 ) print ( 'Hello again! %s' % threading.currentThread()) # 获取Eventloop事件循环 loop = asyncio.get_event_loop() # 执行协程,协程函数不能直接执行,需要放入事件循环才能执行 tasks = [hello(),hello()] loop.run_until_complete(asyncio.wait(tasks)) # 关闭事件循环 loop.close() # 封装两个task任务 end |
async_wget2.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | import asyncio async def wget(host): print ( 'wget %s...' % host) # 创建TCP客户端并连接服务器,或者说创建一个TCP连接对象 # open_connection接收两个参数:主机名和端口号 # connect是协程,这步仅创建协程对象,立即返回,不阻塞 connect = asyncio.open_connection(host, 80 ) # 运行协程连接服务器,这步是阻塞操作,释放CPU # 连接创建成功后,asyncio.open_connection方法返回的就是读写对象 # 读写对象分别为 StreamReader和StreamWriter实例 # 它们也是协程对象,底层调用Socker模块的send和recv方法实现读写 reader,writer = await connect # heade是发送给服务器的消息,意为获取页面的header信息 # 它的格式是固定的 header = 'GET / HTTP/1.0\r\nHost: %s\r\n\r\n' % host # 给服务器发消息,注意消息是二进制的,本次使用utf-8编码 writer.write(header.encode( 'utf-8' )) # writer.drain()是一个与底层IO输入缓冲区交互流量控制方法,需要配合writer.write使用 # 当缓冲区达到上限时,drain()阻塞,待缓冲区回落到下限时,写操作恢复 # 当不需要等待时,drain()会立即返回,假如上面的消息内容较少,不会阻塞 # 这就是一个控制消息数据量的控制阀 await writer.drain() # 给服务器发送消息后,就等着读取服务器返回来的消息 while True : # 读取数据是阻塞操作,释放CPU # reader相当于一个水盆,服务器发来的数据是水流 # readline表示读取一行,以\n作为换行符 # 如果在出现\n之前,数据流出现EOF(End of File文件结束符)也会返回 # 相当于出现\n或EOF时,拧上水龙头,line就是这盆水 line = await reader.readline() # 数据接收完毕,会返回空字符串\r\n,退出while循环,结束数据接收 if line = = b '\r\n' : break # 接收数据是二进制,转换为UTF-8格式并打印 # rstrip()方法删掉字符串结尾就是右边的空白字符,也就是\n print ( '%s header > %s' % (host,line.decode( 'utf-8' ).rstrip())) # 关闭数据流,可以省略 writer.close() await writer.wait_closed() hosts = [ '192.168.1.100' ] hosts = [ 'www.sina.com.cn' , 'www.sohu.com' , 'www.163.com' ] # 创建task任务 tasks = [wget(host) for host in hosts ] # 创建事件循环 loop = asyncio.get_event_loop() # 运行事件循环 loop.run_until_complete(asyncio.wait(tasks)) |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
2017-10-30 Oracle之catalog恢复目录的创建于维护(51CTO风哥rman课程)
2017-10-30 Oracle涂抹oracle学习笔记第8章RMAN说,我能备份