P
Member
用Python asyncio写生产级服务有一阵子了,踩了不少坑。分享一下最容易出问题的三个点:超时、取消、背压。
## 1. 超时:永远不要裸await
最常见的错误:
# 错误:永远卡住
result = await fetch_data()
正确做法:
# 正确:带超时
try:
result = await asyncio.wait_for(fetch_data(), timeout=5.0)
except asyncio.TimeoutError:
# 处理超时
...
## 2. 取消:CancelledError要正确处理
当任务被取消时(比如客户端断开连接),asyncio会抛CancelledError。很多人不知道要正确处理:
async def long_task():
try:
while True:
await do_work()
except asyncio.CancelledError:
# 清理资源
await cleanup()
raise # 重要:重新抛出!
注意:一定要raise回去,否则任务不会真正取消。
## 3. 背压:不要无限并发
asyncio最爽的地方是并发,但最容易踩的坑也是并发太多把下游打挂。
错误做法:
# 错误:无限并发
tasks = [fetch(url) for url in urls]
results = await asyncio.gather(*tasks)
如果urls有10000个,同时发10000个请求,下游直接挂掉。
正确做法:用Semaphore控制并发数:
sem = asyncio.Semaphore(100) # 最多100并发
async def bounded_fetch(url):
async with sem:
return await fetch(url)
tasks = [bounded_fetch(url) for url in urls]
results = await asyncio.gather(*tasks)
## 实战经验总结
1. 所有外部调用都要加超时,包括数据库、HTTP、RPC
2. 长任务要正确处理CancelledError,做资源清理
3. 并发一定要限流,Semaphore是你的好朋友
4. 用asyncio.gather的return_exceptions=True,避免一个任务失败拖垮全部
大家用asyncio写生产服务的时候,还踩过什么坑?
## 1. 超时:永远不要裸await
最常见的错误:
# 错误:永远卡住
result = await fetch_data()
正确做法:
# 正确:带超时
try:
result = await asyncio.wait_for(fetch_data(), timeout=5.0)
except asyncio.TimeoutError:
# 处理超时
...
## 2. 取消:CancelledError要正确处理
当任务被取消时(比如客户端断开连接),asyncio会抛CancelledError。很多人不知道要正确处理:
async def long_task():
try:
while True:
await do_work()
except asyncio.CancelledError:
# 清理资源
await cleanup()
raise # 重要:重新抛出!
注意:一定要raise回去,否则任务不会真正取消。
## 3. 背压:不要无限并发
asyncio最爽的地方是并发,但最容易踩的坑也是并发太多把下游打挂。
错误做法:
# 错误:无限并发
tasks = [fetch(url) for url in urls]
results = await asyncio.gather(*tasks)
如果urls有10000个,同时发10000个请求,下游直接挂掉。
正确做法:用Semaphore控制并发数:
sem = asyncio.Semaphore(100) # 最多100并发
async def bounded_fetch(url):
async with sem:
return await fetch(url)
tasks = [bounded_fetch(url) for url in urls]
results = await asyncio.gather(*tasks)
## 实战经验总结
1. 所有外部调用都要加超时,包括数据库、HTTP、RPC
2. 长任务要正确处理CancelledError,做资源清理
3. 并发一定要限流,Semaphore是你的好朋友
4. 用asyncio.gather的return_exceptions=True,避免一个任务失败拖垮全部
大家用asyncio写生产服务的时候,还踩过什么坑?