線程是操作系統層面的“並行”, 協程是應用程序層面的“並行”。
協程本質上就是:提供一個環境,保存一些需要等待的任務,當這些任務可以執行(等待結束)的時候,能夠執行。再等待的過程中,程序可以執行別的任務。
asyncio是python3.4版本引入到標准庫因此要注意python版本
我的python環境
Python 3.6.5 (v3.6.5:f59c0932b4, Mar 28 2018, 16:07:46) [MSC v.1900 32 bit (Inte l)] on win32 Type "help", "copyright", "credits" or "license" for more information.
平時做接口測試都是使用requests,但是requests是同步的庫,如果想異步的話需要引入aiohttp
- 安裝aiohttp模塊
pip install aiohttp
- 關鍵字async 、await(python3.5開始引入)
async 是明確將函數聲明為協程的關鍵字,函數執行也會返回一個協程對象(async關鍵字可以定義一個協程對象,被async修飾的函數變成了一個協程對象而不是一個普通的函數)(python3.4是使用裝飾器@asyncio.coroutine)
await 在協程函數內部,可以在某個表達式之前使用這個關鍵字來掛起協程,執行別的協程(python3.4是使用yield from)
直接調用異步函數不會返回結果,而是返回一個coroutine對象
可以通過await語法來掛起自身的協程,並等待另一個協程完成直到返回結果
- 關鍵字async with(參考whith的作用:https://www.cnblogs.com/DswCnblog/p/6126588.html)
Aiohttp推薦使用ClientSession作為主要的接口發起請求。ClientSession允許在多個請求之間保存cookie以及相關對象信息。Session(會話)在使用完畢之后需要關閉,關閉Session是另一個異步操作,所以每次你都需要使用async with關鍵字,這樣就不需要單獨再去關閉了
import asyncio import time from aiohttp import ClientSession #async英文為異步的+io操作 url = 'http://127.0.0.1:505?c=1&d=2' #url = 'http://10.21.21.248:8002/sr_sys/v1/user/list' now = lambda: time.time() async def req_get(url): async with ClientSession() as session: async with session.get(url) as response: response = await response.read() #print(response,type(response)) async def req_post(url): async with ClientSession() as session: async with session.post(url) as response: response = await response.read() if __name__ == '__main__': start = now() #方法可以創建一個事件循環,asyncio.BaseEventLoop。 #協程對象不能直接運行,在注冊事件循環的時候,其實是run_until_complete方法將協程包裝成為了一個任務(task)對象。 #所謂task對象是Future類的子類。保存了協程運行后的狀態,用於未來獲取協程的結果 loop = asyncio.get_event_loop() #需要處理的任務 tasks = [asyncio.ensure_future(req_get(url)) for i in range(512)] #tasks = [loop.create_task(req_get(url)) for i in range(512)] 確定參數是協程的時候可以用這個 #將協程注冊到事件循環,並啟動事件循環 #loop.run_until_complete(asyncio.gather(*tasks)) loop.run_until_complete(asyncio.wait(tasks)) for task in tasks: print(task) print('Task ret: ', task.result()) print('TIME: ', now() - start)
aiohttp庫的一些方法具體使用可以參考:https://blog.csdn.net/biheyu828/article/details/87896507
①相關概念的理解:
- event_loop 事件循環:程序開啟一個無限的循環,程序員會把一些函數注冊到事件循環上。當滿足事件發生的時候,調用相應的協程函數。
- coroutine 協程:協程對象,指一個使用async關鍵字定義的函數,它的調用不會立即執行函數,而是會返回一個協程對象。協程對象需要注冊到事件循環,由事件循環調用。
- task 任務:一個協程對象就是一個原生可以掛起的函數,任務則是對協程進一步封裝,其中包含任務的各種狀態。
- future: 代表將來執行或沒有執行的任務的結果。它和task上沒有本質的區別
- async/await 關鍵字:python3.5 用於定義協程的關鍵字,async定義一個協程,await用於掛起阻塞的異步調用接口。
耗時的操作一般是一些IO操作,例如網絡請求,文件讀取等。我們可以使用asyncio.sleep函數來模擬IO操作。協程的目的也是讓這些IO操作異步化。
②ensure_future() asyncio.BaseEventLoop.create_task asyncio.Task三者的區別和取舍:
ensure_future 除了接受 coroutine 作為參數,還接受 future 作為參數。
看 ensure_future 的代碼,會發現 ensure_future 內部在某些條件下會調用 create_task,綜上所述:
- encure_future: 最高層的函數,推薦使用,除了接受coroutine 作為參數,還接受 future 作為參數,
返回一個task - create_task: 在確定參數是 coroutine 的情況下可以使用,因為它只接受協程程序。
- Task: 可能很多時候也可以工作,但真的沒有使用的理由!
參考文檔:
https://www.sohu.com/a/74542662_218897
https://www.cnblogs.com/shenh/p/9090586.html
https://blog.csdn.net/hanglinux/article/details/75068400
https://www.cnblogs.com/zhaof/p/8490045.html
