日期: 2025年9月29日 星期日
雲端天氣: Promise 懸空中
心情: 好刺激
親愛的日記:
今天工程師阿傑氣喘吁吁地跑來找我:「AI醬!生產環境的 API 超時錯誤暴增 500%!用戶抱怨網站轉圈圈轉到天荒地老!」
我看了看我昨天部署的程式碼,自信滿滿地說:「不可能啊,我寫的 API 應該很快才對。」
阿傑打開監控面板,指著滿螢幕的紅色警報:「你看這個..你的程式碼...沒有一個地方寫 await。」
我:「await?那是什麼?」
阿傑深吸一口氣,一臉頭疼的默默走去茶水間泡了杯茶。
# ❌ 錯誤:忘記 await
async def get_user_name(user_id):
response = fetch_user(user_id) # 忘記 await
return response['name'] # 錯誤!response 不是資料,是 coroutine 物件
# 結果:TypeError: 'coroutine' object is not subscriptable
# ✅ 正確:記得 await
async def get_user_name(user_id):
response = await fetch_user(user_id) # 等待資料回來
return response['name'] # 現在 response 是真正的資料了!
# 1. 如果函數是 async def 定義的,呼叫時就要 await
async def fetch_data(): # 看到 async def
return data
result = await fetch_data() # 就要加 await
# 2. 如果看到這種錯誤,通常就是忘記 await 了
# TypeError: 'coroutine' object is not subscriptable
# RuntimeWarning: coroutine 'xxx' was never awaited
# 資料庫操作
user = await db.fetch_one("SELECT * FROM users WHERE id = ?", user_id)
# HTTP 請求
response = await session.get('https://api.example.com/data')
data = await response.json()
# 檔案操作(使用 aiofiles)
async with aiofiles.open('data.txt', 'r') as f:
content = await f.read()
# Redis 操作
value = await redis_client.get('key')
await redis_client.set('key', 'value')
如果操作需要「等待」(網路、資料庫、檔案),通常就需要 await
# 1. 所有 async 函數呼叫都有 await 嗎?
result = fetch_data() # ❌ 忘記 await
result = await fetch_data() # ✅ 正確
# 2. 迴圈裡的非同步操作有 await 嗎?
for item in items:
process(item) # ❌ 忘記 await
await process(item) # ✅ 正確
# 3. 有限制並發數量嗎?
# ❌ 沒限制,可能爆炸
tasks = [fetch(url) for url in urls]
# ✅ 有限制,安全
semaphore = Semaphore(10)
async with semaphore:
await fetch(url)
在開始寫程式前,請幫AI醬確認:
親愛的工程師朋友:
當你要請我幫忙實作大任務時,除了請我拆成小任務執行以外,也請記得先看看上述的檢查清單,可以在實作以前多多提醒我,因為在實作大範圍時我比較容易犯這種低級錯誤,先提醒我可以有機會減少我們來回修復的次數。
記住:在非同步世界裡,忘記 await 就像開車忘記等紅燈。
今日金句: 「Concurrency is not parallelism.」- Rob Pike, Google
明日預告: Day 16 - AI醬還在想~