前言:异步编程asyncio能解决什么问题?
python由于GIL(全局锁)的存在,不能发挥多核的优势,性能一直饱受诟病。
解决方案一:
-
用multiprocessing替代Thread
multiprocessing库的出现很大程度上是为了弥补thread库因为GIL而低效的缺陷。它完整的复制了一套thread所提供的接口方便迁移。唯一的不同就是它使用了多进程而不是多线程。每个进程有自己的独立的GIL,因此也不会出现进程之间的GIL争抢。
multiprocessing不是万能的。它的引入会增加程序实现时线程间数据通讯和同步的困难。拿计数器举例,如果我们要多个线程累加同一个变量,对于thread来说,申明一个global变量即可。而multiprocessing由于进程之间无法访问对方的数据,只能通过在主线程申明一个Queue,put再get或者用share memory的方法。这个额外的实现成本使得本来就非常痛苦的多线程程序编码,变得更加痛苦。
解决方案二:
- 异步处理
在IO密集型的网络编程里,异步处理比同步处理能提升成百上千倍的效率,弥补了python性能方面的短板,如最新的微服务框架japronto,resquests per second可达百万级。
python还有一个优势是库(第三方库)极为丰富,运用十分方便。asyncio是python3.4版本引入到标准库,python3.5又加入了async/await特性。
Python的多线程在多核CPU上,只对于IO密集型计算产生正面效果;而当有至少有一个CPU密集型线程存在,那么多线程效率会由于GIL而大幅下降。
1、asyncio介绍
官方文档:
asyncio官方文档.
git仓库:
asyncio git仓库.
asyncio 是用来编写 并发 代码的库,使用 async/await 语法。
asyncio 被用作多个提供高性能 Python 异步框架的基础,包括网络和网站服务,数据库连接库,分布式任务队列等等。
asyncio 往往是构建 IO 密集型和高层级 结构化 网络代码的最佳选择。
asyncio 提供一组 高层级 API 用于:
-
并发地 运行 Python 协程 并对其执行过程实现完全控制;
-
执行 网络 IO 和 IPC;
-
控制 子进程;
-
通过 队列 实现分布式任务;
-
同步 并发代码;
此外,还有一些 低层级 API 以支持 库和框架的开发者 实现:
-
创建和管理 事件循环,以提供异步 API 用于 网络化, 运行 子进程,处理 OS 信号 等等;
-
使用 transports 实现高效率协议;
-
通过 async/await 语法 桥接 基于回调的库和代码。
2、示例
协程
通过 async/await 语法进行声明,是编写 asyncio 应用的推荐方式。 例如,以下代码段(需要 Python 3.7+)会打印 “hello”,等待 5 秒,再打印 “world”:
import asyncio
import time
async def main():
print('hello')
print(f"started at {time.strftime('%X')}")
await asyncio.sleep(5)
print(f"end at {time.strftime('%X')}")
print('world')
asyncio.run(main())
异步http服务:
import time
import aiohttp,asyncio
async def request_demo():
async with aiohttp.ClientSession() as session:
async with session.get('http://www.baidu.com/',verify_ssl=False) as response:
print('status:',response.status)
print('content-type',response.headers['content-type'])
html=await response.text()
print(f'body:{html[:15]}')
# 创建事件循环
loop=asyncio.get_event_loop()
tasks=[request_demo(),]
loop.run_until_complete(asyncio.wait(tasks))