看到標題的朋友可能會覺得奇怪, 我們常常看到的不就是time.sleep嗎? 怎麼又多出了asyncio.sleep呢? 這兩者究竟差異在哪邊呢?
我們都知道sleep就是睡眠的意思, 那麼在程式的運作上就是等待, 等待一段時間之後繼續完成任務, time.sleep的部份很好理解, 就是在該段程式碼的地方等待, 直到時間結束繼續往下做, 而這會是一個阻塞的行為, 假設有多個任務需要切換時會較為不利。
而asyncio.sleep則是用於非同步的設計方式, 關於非同步的知識歡迎參考「【Python - asyncio】非同步 I/O 簡介」, 它可以讓我們在某個點等待一段時間, 讓事件處理循環先處理其他任務後再切回原任務繼續執行, 讓我們感覺起來具有連貫性, 但其實背後是一連串有效率的資源應用功能。
asyncio.sleep與time.sleep兩者之間的差異可見下圖:
這就是非同步程式的一個魅力之一, 讓我們不會因為一個等待而導致後面的塞車, 進而發揮了單一執行緒的最佳資源使用效用。
來看看下面這段程式碼, 我們創造了兩個任務,每個任務都會執行一段無窮迴圈, 並印出各自任務的號碼, 那麼假設我們照著流程執行時, 會發現到只印出「1」…
import asyncio
async def job(num: int):
while True:
print(f"{num}")
async def main():
task1 = asyncio.create_task(job(1))
task2 = asyncio.create_task(job(2))
await asyncio.gather(task1, task2)
asyncio.run(main())
我們來看看印出後的結果…
1
1
1
1
1
1
1
但其實我們希望兩個任務是互相切換的, 因此我們可以加上asyncio.sleep來讓兩個任務之間產生出一個間隙,就像這樣:
import asyncio
async def job(num: int):
while True:
await asyncio.sleep(0.001)
print(f"{num}")
async def main():
task1 = asyncio.create_task(job(1))
task2 = asyncio.create_task(job(2))
await asyncio.gather(task1, task2)
asyncio.run(main())
我們可以看到兩者之間就能夠切換著執行了…
1
2
1
2
1
2
1
2
1
2
1
2
同樣都是sleep, 卻有不同的作用, 每項功能被設計出來都是有其意義的, 因此我們只要好好的掌握這些技巧, 就能夠將程式發揮的淋漓盡致。