如果你想了解非同步程式設計,那麼必然會涉及出許多相關概念。
- 堵塞/非堵塞
- 同步/非同步
- 多程式/多執行緒/協程
為什麼我要學習這個話,因為我想搞懂非同步框架和非同步介面的呼叫。所以,我的學習路線是這樣的:
1.python非同步程式設計
2.python Web非同步框架(tornado/sanic)
3.非同步介面呼叫(aiohttp/httpx)
那麼非同步程式設計有什麼好處?在某些場景下它可以提高效能。我們知道CPU的速度快於磁碟、網路等IO。一旦遇到IO操作,如讀寫檔案、傳送網路資料時,就需要等待IO操作完成,才能進行下一步操作。這種情況稱為同步IO。我們可以使用多執行緒來解決這類問題,另一種方式是通過非同步。
python在3.4版本引入asyncio,到 3.5版本又加入async/await來簡化非同步的使用。
先來舉個簡單的例子,假如,你和女朋友逛街。你的目的是去看新上市的華為P40手機,而你女朋友是去看新款的衣服。你們的逛街流程是這樣的。
import time
def clothes_shop():
print("女朋友看衣服..")
time.sleep(8)
print("...出來了")
def huawei_shop():
print("體驗手機..")
time.sleep(5)
print("...出來了")
print(time.ctime(), "開始逛街")
clothes_shop()
huawei_shop()
print(time.ctime(), "結束.")
執行結果:
Thu Apr 16 00:08:22 2020 開始逛街
女朋友看衣服..
...出來了
體驗手機..
...出來了
Thu Apr 16 00:08:35 2020 結束.
假設單位是分鐘,你們總共耗時13分鐘。
接下來,看看用非同步是如何處理的:
import asyncio
import time
async def shop(delay, what):
print(what)
await asyncio.sleep(delay)
print("...出來了")
async def main():
task1 = asyncio.create_task(shop(8, '女朋友看衣服..'))
task2 = asyncio.create_task(shop(5, '體驗手機..'))
print(time.ctime(), "開始逛街")
await task1
await task2
print(time.ctime(), "結束.")
asyncio.run(main())
通過 async/await 語法進行宣告,是編寫 asyncio 應用的推薦方式。
- async 宣告一個函式為非同步函式。
- await 宣告處理比較耗費時的動作。
- asyncio.run() 函式用來執行最高層級的入口點 main() 函式。
- asyncio.create_task() 函式用來併發執行作為 asyncio 任務 的多個協程。
其實,思路非常簡單,就是你和女朋友各逛各自的,先出來的等等對方。
嚴重警告!提醒廣大直男,現實生活中千萬不要這麼思考問題。一定要陪女朋友一起看衣服,還要主動去付錢。
來看看執行結果:
Thu Apr 16 00:19:19 2020 開始逛街
女朋友看衣服..
體驗手機..
...出來了
...出來了
Thu Apr 16 00:19:27 2020 結束.
假設單位是分鐘,只需要8分鐘搞定。
通過上面的例子,可以看到 task1、task2仍然有前後順序,這種前後順序的時間可以忽略不計。但是,我們也是可以使用asyncio.gather()方法併發執行任務。
#……
async def main():
print(time.ctime(), "開始逛街")
await asyncio.gather(
shop(8, '女朋友看衣服..'),
shop(5, '體驗手機..')
)
print(time.ctime(), "結束.")
asyncio.run(main())
執行結果同上,這裡就不再貼了。