隨著網路應用與 I/O 密集型工作越來越普遍,Python 的非同步程式設計變得非常重要。本篇文章將帶你了解 Python 中 async
/ await
的用法,並介紹 asyncio
模組的基本概念與範例。
什麼是非同步程式設計?
非同步程式設計讓你能夠在等待 I/O(像是網路請求、檔案讀寫)時,不會阻塞整個程式,而是把時間留給其他工作繼續執行,提高效率。
Python 的 async 與 await
async def
:定義非同步函式(協程 coroutine)await
:等待一個協程或非同步任務完成
範例:定義與呼叫非同步函式
import asyncio
async def say_hello():
print("Hello")
await asyncio.sleep(1) # 非同步等待 1 秒
print("World")
asyncio.run(say_hello())
asyncio 模組簡介
Python 的 asyncio
是標準庫裡負責非同步事件循環的模組,主要用來調度與執行多個協程。
同時執行多個協程:asyncio.gather()
import asyncio
async def task(id, delay):
print(f"Task {id} 開始")
await asyncio.sleep(delay)
print(f"Task {id} 結束")
return id * 10
async def main():
results = await asyncio.gather(
task(1, 2),
task(2, 1),
task(3, 3),
)
print("結果:", results)
asyncio.run(main())
控制非同步併發數量(類似 ThreadPoolExecutor)
當你有一個參數列表,想非同步呼叫很多工作,但想限制同時執行的任務數量(例如同時最多 3 個),可以用 asyncio.Semaphore
來做到。
import asyncio
async def worker(sem, param):
async with sem: # 申請 Semaphore,限制同時併發數
print(f"開始處理 {param}")
await asyncio.sleep(2) # 模擬 I/O 工作
print(f"完成處理 {param}")
async def main(params):
sem = asyncio.Semaphore(3) # 同時最多允許3個併發
tasks = [asyncio.create_task(worker(sem, p)) for p in params]
await asyncio.gather(*tasks)
params = list(range(10))
asyncio.run(main(params))
這樣即使建立了 10 個任務,也會同時最多執行 3 個,避免過度佔用資源。
錯誤處理
非同步函式裡也可以用 try/except
捕捉例外,錯誤會往上拋,讓你能集中處理。
async def might_fail():
await asyncio.sleep(1)
raise ValueError("出錯了!")
async def main():
try:
await might_fail()
except ValueError as e:
print("捕捉到錯誤:", e)
asyncio.run(main())
非同步 vs 同步的比較
面向 | 同步 | 非同步 |
---|---|---|
執行模式 | 逐步等待完成 | 可同時等待多個任務 |
資源使用 | 可能阻塞,浪費等待時間 | 更有效率,充分利用等待時間 |
程式設計 | 直觀,但對I/O不友好 | 需設計非同步流程,較複雜 |
小結
- 使用
async def
和await
寫非同步函式 - 利用
asyncio.run()
啟動事件循環 - 用
asyncio.gather()
可以同時跑多個協程 - 用
asyncio.Semaphore
控制同時執行數量,避免過度佔用資源 - 用
try/except
做非同步錯誤處理 - 非同步適合 I/O 密集、等待較長的場景
如果你想了解更進階的非同步網路程式設計(如 aiohttp)、資料庫非同步操作,或事件循環底層運作,歡迎留言討論!
沒有留言:
張貼留言