from flask import Flask
import time
app = Flask(__name__)
@app.route('/')
def index():
    time.sleep(3)
    return 'Hello!'
if __name__ == '__main__':
    app.run(threaded=True)

flask提供web页面

import asyncio
import aiohttp
import time
start = time.time()
async def get(url):
    session = aiohttp.ClientSession()
    response = await session.get(url)
    result = await response.text()
    await session.close()
    return result
async def request():
    url = 'http://127.0.0.1:5000'
    print('Waiting for', url)
    result = await get(url)
    print('Get response from', url, 'Result:', result)

# asyncio.ensure_future定义task对象,以在run_until_complete方法中运行
tasks = [asyncio.ensure_future(request()) for _ in range(5)]
# asyncio.get_event_loop()创建事件循环loop
loop = asyncio.get_event_loop()
# asyncio.wait的参数必须是task对象组成的列表,表示执行多次请求,使用方法和gevent相似
loop.run_until_complete(asyncio.wait(tasks))
# loop.run_until_complete(asyncio.gather(*tasks))
end = time.time()
print('Cost time:', end - start)

使用aiohttp提供的异步协程

结果如下

Waiting for http://127.0.0.1:5000
Waiting for http://127.0.0.1:5000
Waiting for http://127.0.0.1:5000
Waiting for http://127.0.0.1:5000
Waiting for http://127.0.0.1:5000
Get response from http://127.0.0.1:5000 Result: Hello!
Get response from http://127.0.0.1:5000 Result: Hello!
Get response from http://127.0.0.1:5000 Result: Hello!
Get response from http://127.0.0.1:5000 Result: Hello!
Get response from http://127.0.0.1:5000 Result: Hello!
Cost time: 3.0199508666992188

对比单线程

import requests
import time
start = time.time()
def request():
    url = 'http://127.0.0.1:5000'
    print('Waiting for', url)
    result = requests.get(url).text
    print('Get response from', url, 'Result:', result)
for _ in range(100):
    request()
end = time.time()
print('Cost time:', end - start)

最后耗时:

Cost time: 305.16639709472656

从 Python 3.4 开始,Python 中加入了协程的概念,但这个版本的协程还是以生成器对象为基础的,在 Python 3.5 则增加了 async/await,使得协程的实现更加方便。其中,async 定义一个协程,await 用来挂起阻塞方法的执行。

Python 中使用协程最常用的库莫过于 asyncio,所以本文会以 asyncio 为基础来介绍协程的使用。

基本概念:

event_loop:事件循环,相当于一个无限循环,可以把一些函数注册到这个事件循环上,当满足条件发生的时候,就会调用对应的处理方法。

coroutine:中文翻译叫协程,在 Python 中常指代为协程对象类型,可以将协程对象注册到事件循环中,它会被事件循环调用。可以使用 async 关键字来定义一个方法,这个方法在调用时不会立即被执行,而是返回一个协程对象。

task:任务,它是对协程对象的进一步封装,包含了任务的各个状态。

future:代表将来执行或没有执行的任务的结果,实际上和 task 没有本质区别