Python2 时代高性能的网络编程主要是 Twisted、Tornado 和 Gevent 这三个库,但是它们的异步代码相互之间既不兼容也不能移植。Gvanrossum 希望在 Python 3 实现一个原生的基于生成器的协程库,其中直接内置了对异步 IO 的支持,这就是 asyncio,它在 Python 3.4 被引入到标准库。
并发对比
asyncio 使用单线程、单个进程的方式切换(通常程序等待读或写数据时就是切换上下文的时机)。
requests + ThreadPoolExecutor
这里采用的是线程池 + 同步方式,requests 仅支持同步方式:
import time
import requests
from concurrent.futures import ThreadPoolExecutor
numbers = range(12)
url = 'http://httpbin.org/get?a={}'
def fetch(a):
print(a)
r = requests.get(url.format(a))
return r.json()['args']['a']
start = time.time()
# 开三个线程
with ThreadPoolExecutor(max_workers=3) as executor:
for num, result in zip(numbers, executor.map(fetch, numbers)):
print('fetch({})'.format(num, result))
print('使用 requests + ThreadPoolExector 总耗时:{}'.format(time.time() - start)) # 5.696202754974365
asyncio + aiohttp
协程+异步,现在的 asyncio,有了很多的模块已经在支持:aiohttp,aiodns,aioredis 等等 https://github.com/aio-libs:
import asyncio
import time
import aiohttp
url = 'http://httpbin.org/get?a={}'
numbers = range(12)
async def fetch(a):
async with aiohttp.ClientSession() as session:
async with session.get(url.format(a)) as resp:
data = await resp.json()# 等待结果
return data['args']['a']
start = time.time()
event_loop = asyncio.get_event_loop()# 新建事件循环
tasks = [fetch(num) for num in numbers]# 添加到任务列表
# asyncio.gather() 按顺序搜集异步任务执行的结果
results = event_loop.run_until_complete(asyncio.gather(*tasks))# 开启事件循环
for num, result in zip(numbers, resu