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 沒有本質區別。