第一集:阻塞與非阻塞的世界
傳統的同步編程會讓程式在等待 IO 操作(如網路請求或檔案讀寫)時完全停止(阻塞)。
異步編程(Asynchronous Programming)的目標是允許程式在等待 IO 完成的同時,可以切換去做其他有意義的工作(非阻塞)。這對於需要處理大量併發連接的網路應用程式(如 FastAPI 伺服器)至關重要。
核心概念:
IO Bound (I/O 密集型): 程式大部分時間都在等待外部操作。異步編程對此類任務最有幫助。
CPU Bound (CPU 密集型): 程式大部分時間都在執行計算。這類任務應使用多進程 (Multiprocessing)。
第二集:Async/Await 與 Event Loop
在 Python 中,我們主要使用 async 和 await 關鍵字來定義和呼叫協程(Coroutines)。
協程是異步編程的基本單元,它可以在執行過程中暫停並讓出控制權。
Python
import asyncio
async def say_hello(delay, what):
await asyncio.sleep(delay) # 暫停並讓出控制權
print(what)
async def main():
# 同時啟動多個協程
await asyncio.gather(
say_hello(3, "Hello after 3s"),
say_hello(1, "World after 1s")
)
# 啟動 Event Loop
asyncio.run(main())
**Event Loop(事件循環)**是 asyncio 的核心,它負責監控所有正在等待的協程,並在 IO 準備就緒時,將控制權交還給對應的協程。
第三集:Asyncio 實際應用:HTTP 請求
要讓異步編程發揮作用,我們必須使用異步版本的函式庫。例如,進行 HTTP 請求時,我們不應使用同步的 requests 函式庫,而應該使用異步的 httpx 或 aiohttp。
以下是使用 httpx 異步發送請求的簡單範例:
Python
import httpx
import asyncio
async def fetch_url(url):
async with httpx.AsyncClient() as client:
response = await client.get(url)
print(f"Fetched {url}: {len(response.text)} bytes")
async def run_multiple_fetches():
urls = ["https://example.com", "https://google.com"]
tasks = [fetch_url(url) for url in urls]
# 同時等待所有請求完成
await asyncio.gather(*tasks)
if __name__ == '__main__':
asyncio.run(run_multiple_fetches())
這種方式能極大地提高併發處理網路請求的效率。