Python并发最佳实践
TaskGroup 优先用于有生命周期的并发
Python 3.11 的 asyncio.TaskGroup 适合一组必须一起成功或一起失败的子任务。退出上下文时会等待所有任务;其中一个任务抛异常,其余任务会被取消,异常以 ExceptionGroup 汇总。
async with asyncio.TaskGroup() as group:
group.create_task(fetch_user(user_id))
group.create_task(fetch_orders(user_id))asyncio.gather 更适合已有一组 awaitable、只想收集结果的场景。默认一个异常会向调用方传播,但其他任务不一定立刻停止;不要把它当成完整的取消边界。
限速与清理
limit = asyncio.Semaphore(10)
async def bounded_fetch(url):
async with limit:
return await client.get(url)- 用
create_task后必须保存任务引用并 await,避免异常悄悄丢失。 - 网络客户端要在应用生命周期中复用,别在每个协程里新建连接池。
- 取消时仍要在
finally中释放文件、锁和临时资源。
请求层应该单独设置超时;超时并不等同于取消整个批次,是否继续处理其他任务要由业务语义决定。
如果任务之间没有失败联动需求,gather 配合 return_exceptions=True 可以收集每项结果,但调用端必须逐个处理异常对象。