Python 进阶学习笔记之五:异步 IO

Python 进阶系列笔记文章链接:
Python 进阶学习笔记之一:内置常用类型及方法
Python 进阶学习笔记之二:常用数据类型(上)
Python 进阶学习笔记之三:常用数据类型(下)
Python 进阶学习笔记之四:高效迭代器工具
Python 进阶学习笔记之五:异步 IO
Python 进阶学习笔记之六:多线程编程
Python 进阶学习笔记之七:互联网支持
Python 进阶学习笔记之八:面向对象高级编程
Python 进阶学习笔记之九:IO 编程
Python 进阶学习笔记之十:一般加密支持
Python 进阶学习笔记之十一:日志支持
Python 进阶学习笔记之十二:数据压缩与归档

编程中,我们经常会遇到“并发”这个概念,目的是让软件能充分利用硬件资源,提高性能。并发的方式有多种,多线程,多进程,异步IO等。多线程和多进程更多应用于CPU密集型的场景,比如科学计算的时间都耗费在CPU上,利用多核CPU来分担计算任务。多线程和多进程之间的场景切换和通讯代价很高,不适合IO密集型的场景,而异步IO就是非常适合IO密集型的场景,比如网络爬虫和Web服务。

在计算机程序中,IO就是读写磁盘、读写网络的操作,这种读写速度比读写内存、CPU缓存慢得多,前者的耗时是后者的成千上万倍甚至更多。这就导致,IO密集型的场景99%以上的时间都花费在IO等待的时间上。异步IO就是把CPU从漫长的等待中解放出来的方法。这就可以大大提高我们写的软件系统的并发性。

asyncio - 异步 IO

asyncio 模块用于支持异步 IO 编程和并发编程,这个模块是从 3.4版本引入的标准库,在后续的几个小版本中一直在增强,3.7 中也增加了一些高层次的 API,本文会略有介绍。关于并发编程,在任何高级语言中都是一门很深奥的知识分支,本笔记进作为入门知识,如果要深入研究,请参阅专门的专题或书籍。

Python 3.6 版本后 asyncio模块已经代替了原来的 asyncore模块(异步Sockt 处理)和 asynchat模块(异步 Socket 指令),因此3.6+版本的 python 推荐使用此模块进行异步执行和异步通信的编码实现。

协程与任务

入门使用

在 Python 中,一个异步执行单元叫做 协程,协程通过 async/await 语法进行声明,是编写异步应用的推荐方式。
简单示例:

import asyncio

async def main():
     print('hello')
     await asyncio.sleep(1)
     print('world')
     
asyncio.run(main())       #  注意,上面的协程函数 main 直接调用并不会执行

要真正运行一个协程,asyncio 提供了三种主要机制:

  1. asyncio.run()函数用来运行最高层级的入口点 “main()” 函数 (参见上面的示例)
  2. 等待一个协程,即用 await来修饰一个协程,需要注意的是 await只能用于函数内部,因此上面的例子如果要改用 await的话,还需要稍加修改
    async def run_main():
    	await main()
    	
    asyncio.run(run_main())
    
  3. 使用 asyncio.create_task()函数用来并发运行多个协程
    import asyncio
    
     async def foo(thread_name):
     	c = 1
     	while c < 5:
         	print(f"{thread_name}: {c}")
         	c = c + 1
         	await asyncio.sleep(1)
    
    
     async def main_run():
     	t1 = asyncio.create_task(foo("t1"))
     	t2 = asyncio.create_task(foo("t2"))      # 3.7+ 版本推荐使用 create_task 创建 task
    
     	t3 = asyncio.ensure_future(foo("t3"))   # 3.7 以前版本使用此方法创建 task
    
     	await t1
     	await t2
     	await t3
    
     asyncio.run(main_run()) 
    

task 的目的之一就是支持 并发 执行多个 协程,当一个协程通过 asyncio.create_task()等函数被打包为一个 任务,该协程将自动排入日程准备立即运行。

上面列子中还需要关注的点:

  • asyncio.run(coro, *, debug=False):运行 asyncio 程序入口,如果 debug 参数为 True,事件循环将以调试模式运行。
  • asyncio.create_task(coro):将 coro 协程 打包为一个 Task 排入日程准备执行。返回 Task 对象。此函数 在 Python 3.7 中被加入。在 Python 3.7 之前,可以改用低层级的 asyncio.ensure_future()函数。
  • asyncio.sleep(delay, result=None, *, loop=None): 阻塞 delay 指定的秒数,也就是 休眠 ,注意这个函数本身是个协程函数,需要使用 await进行调用。

并发运行任务

函数 asyncio.gather(*aws, loop=None, return_exceptions=False)用来支持并发 task 的执行,第一个参数支持多个协程对象,如果所有可等待(协程)对象都成功完成,结果将是一个由所有返回值聚合而成的列表,结果值的顺序与 aws 中可等待对象的顺序一致。
示例:

import asyncio

async def factorial(name, number):
    f = 1
    for i in range(2, number + 1):
        print(f"Task {name}: Compute factorial({i})...")
        await asyncio.sleep(1)
        f *= i
    print(f"Task {name}: factorial({number}) = {f}")

async def main():
    await asyncio.gather(
        factorial("A", 2),
        factorial("B", 3),
        factorial("C", 4),
    )

asyncio.run(main()
  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值