【asyncio】異步編程知識(shí)總結(jié)

1. 基礎(chǔ)概念
1.1 協(xié)程概念
協(xié)程(Coroutine),也稱為微線程,是一種用戶態(tài)內(nèi)的上下文切換技術(shù)。其實(shí)就是通過(guò)一個(gè)線程實(shí)現(xiàn)代碼塊相互切換執(zhí)行。
實(shí)現(xiàn)協(xié)程的幾種方法:
greentlet ,手動(dòng)switch切換
yield關(guān)鍵字
asyncio裝飾器(py3.4+),遇到IO自動(dòng)切換。
async、await他關(guān)鍵字(py3.5,推薦)
協(xié)程的目的是通過(guò)一個(gè)線程利用其IO等待的時(shí)候,再去干點(diǎn)別的事情,別閑著!
1.2 事件循環(huán)
可以把事件循環(huán)當(dāng)作一個(gè)while True循環(huán),監(jiān)測(cè)并執(zhí)行某些代碼。
1.3 協(xié)程函數(shù)和協(xié)程對(duì)象
協(xié)程函數(shù): 定義函數(shù)格式為async def 函數(shù)名。
協(xié)程對(duì)象: 協(xié)程函數(shù)()?得到的對(duì)象。
注意: result = func()創(chuàng)建協(xié)程對(duì)象,函數(shù)內(nèi)部代碼不會(huì)執(zhí)行。
如果要運(yùn)行協(xié)程函數(shù)內(nèi)部代碼,必須要將協(xié)程對(duì)象交給事件循環(huán)來(lái)處理。
1.4 await關(guān)鍵字
await后跟可等待對(duì)象,可等待對(duì)象包括協(xié)程對(duì)象、Future和Task對(duì)象,這些都是IO等待。等IO操作完成之后再繼續(xù)往下執(zhí)行,當(dāng)前協(xié)程(任務(wù))掛起時(shí),事件循環(huán)可以執(zhí)行其他協(xié)程(任務(wù))。
同一個(gè)協(xié)程任務(wù)中,多個(gè)await,會(huì)依次等待等待對(duì)象執(zhí)行完成;不同協(xié)程任務(wù)中,遇到await會(huì)交替執(zhí)行。
案例1:

案例2:
運(yùn)行結(jié)果:

1.5 Task對(duì)象
Tasks are used to schedule coroutines concurrently.??
?When a coroutine is wrapped into a Task with functions like asyncio.create_task() the coroutine is automatically scheduled to run soon.
Task被用來(lái)在事件循環(huán)中添加多個(gè)任務(wù)的。
當(dāng)協(xié)程包裝到具有asyncio.create_task()等函數(shù)的任務(wù)中時(shí),會(huì)自動(dòng)地添加到事件循環(huán)中等待被調(diào)度執(zhí)行。除了使用asynico.create_task()函數(shù)以外,還可以用底層級(jí)的loop.create_create_task()或ensure_future()函數(shù)。
注意: asynico.create_task()函數(shù)在py3.7中被加入。在py3.7之前,可以改用低層級(jí)的asyncio.ensure_future()函數(shù)。
create_task源碼,獲取正在運(yùn)行的事件循環(huán),然后在事件循環(huán)里把任務(wù)core添加進(jìn)去,最后返回一個(gè)Task對(duì)象。
案例1:

案例2:

案例3:

和案例2相比,task_list中直接寫的任務(wù)名稱,沒有通過(guò)create_task創(chuàng)建Task對(duì)象,這是因?yàn)閏reate_task函數(shù)創(chuàng)建任務(wù)之后會(huì)自動(dòng)添加到事件循環(huán)中,在該案例中定義task_list前還沒有創(chuàng)建事件循環(huán),但是通過(guò)asyncio.wait()可以將任務(wù)添加到asyncio.run()創(chuàng)建的事件循環(huán)中。
1.6 asyncio.Future對(duì)象
A Future is a special low-level awaitable object that represents an eventual result of an asynchronous operation.
asyncio中的Future對(duì)象是一個(gè)更偏向底層的可等待對(duì)象,代表異步任務(wù)的最終結(jié)果。通常不會(huì)直接用到這個(gè)對(duì)象,而是直接使用Task對(duì)象來(lái)完成任務(wù)的創(chuàng)建和狀態(tài)的追蹤。
Task繼承Future,Task對(duì)象內(nèi)部await結(jié)果是基于Future對(duì)象來(lái)的。
案例1:
案例2:
1.7 異步和非異步模塊混合使用
python還有一個(gè)concurrent.futures.Future對(duì)象,它和asyncio.Future是不一樣的。concurrent.futures.Future對(duì)象不可以用await修飾,asyncio.Future對(duì)象可以用await修飾。
但是asyncio提供了一個(gè)方法asyncio.wrap_future()可以將concurrent.futures.Future對(duì)象轉(zhuǎn)換為asyncio.Future。
案例: asyncio + 不支持異步的模塊
1.8 異步迭代器
異步迭代器
實(shí)現(xiàn)了__aiter__()和__anext__()方法的對(duì)象。__anext__必須返回一個(gè)awaitable對(duì)象。async for會(huì)處理異步迭代器的__anext__()方法所返回的可等待對(duì)象,直到其引發(fā)一個(gè)StopAsyncIteration異常。
異步可迭代對(duì)象
可在async for語(yǔ)句中被使用的對(duì)象。必須通過(guò)它的__aiter__()方法返回一個(gè)asynchronous iterator。
案例1:
async for要寫在async函數(shù)里,不然會(huì)報(bào)錯(cuò):SyntaxError: 'async for' outside async function
1.9 異步上下文管理器
異步上下文管理器就是對(duì)象通過(guò)定義__aenter__()和__aexit__()方法來(lái)對(duì)async with語(yǔ)句中的環(huán)境進(jìn)行控制。
可以通過(guò)with open來(lái)理解,enter中打開文件,exit中關(guān)閉文件。
案例:
1.10 uvloop
uvloop是asyncio的事件循環(huán)的替代方案。uvloop的事件循環(huán)效率高于默認(rèn)asyncio的事件循環(huán)。
注: uvloop不支持window平臺(tái),安裝會(huì)報(bào)錯(cuò);ubuntu上測(cè)試是可以正常安裝的。

注意:一個(gè)asgi->uvicorn內(nèi)部使用的就是uvloop
案例:
2. 案例學(xué)習(xí)
2.1 異步redis
在使用python代碼操作redis時(shí),連接/操作/斷開都是網(wǎng)絡(luò)IO。
環(huán)境: aioredis 2.0.1
案例:
redis庫(kù)中存放的數(shù)據(jù):

從redis庫(kù)中讀取數(shù)據(jù):

2.2 異步MySQL
環(huán)境: aiomysql 0.1.1

案例:

2.3 異步FastAPI
環(huán)境:
fastapi 0.88.0 pip install fastapi
uvicorn 0.20.0 pip install uvicorn
案例:

2.4 異步爬蟲
環(huán)境:
aiohttp 3.8.3 pip install aiohttp?
案例:

?3. 參考資料
BIlibili學(xué)習(xí)視頻: BV1Ke411W71L (非常好的入門課程)
asyncio官方文檔:https://docs.python.org/zh-cn/3.8/library/asyncio.html
事件循環(huán): https://docs.python.org/zh-cn/3.8/library/asyncio-eventloop.html
Task對(duì)象: https://docs.python.org/zh-cn/3.8/library/asyncio-task.html#awaitables
asyncio和線程、進(jìn)程混用: https://docs.python.org/3.8/library/asyncio-eventloop.html#asyncio.loop.run_in_executor
aioredis官方文檔:https://aioredis.readthedocs.io/en/latest/
aiomysql官方文檔: https://aiomysql.readthedocs.io/en/latest/index.html
Ubuntu上安裝MySQL: https://kalacloud.com/blog/ubuntu-install-mysql/#:~:text=%E5%A6%82%E4%BD%95%E5%9C%A8%20Ubuntu%20%E4%B8%8A%E5%AE%89%E8%A3%85%20MySQL%201%20%E7%AC%AC%E4%B8%80%E6%AD%A5%20-%20%E5%AE%89%E8%A3%85,MySQL%20%E6%98%AF%E4%B8%8D%E6%98%AF%E5%AE%8C%E5%85%A8%E5%AE%89%E8%A3%85%E6%88%90%E5%8A%9F%20%E8%B5%B0%E5%88%B0%E8%BF%99%E9%87%8C%EF%BC%8C%E6%88%91%E4%BB%AC%E5%8F%AF%E4%BB%A5%E7%94%A8%20service%20%E5%91%BD%E4%BB%A4%EF%BC%8C%E7%9C%8B%E4%B8%80%E4%B8%8B%20mysql%20%E8%BF%99%E4%B8%AA%E6%9C%8D%E5%8A%A1%E6%98%AF%E4%B8%8D%E6%98%AF%E6%AD%A3%E5%B8%B8%E5%9C%A8%E8%BF%90%E8%A1%8C%E3%80%82%20