2025年5月31日 星期六

Python 非同步程式設計入門:async/await 與 asyncio 基本教學

隨著網路應用與 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 defawait 寫非同步函式
  • 利用 asyncio.run() 啟動事件循環
  • asyncio.gather() 可以同時跑多個協程
  • asyncio.Semaphore 控制同時執行數量,避免過度佔用資源
  • try/except 做非同步錯誤處理
  • 非同步適合 I/O 密集、等待較長的場景

如果你想了解更進階的非同步網路程式設計(如 aiohttp)、資料庫非同步操作,或事件循環底層運作,歡迎留言討論!

沒有留言: