0

0

asyncio.timeout() 在 3.11+ 如何与 gather/wait 配合使用

冰川箭仙

冰川箭仙

发布时间:2026-01-25 20:47:52

|

742人浏览过

|

来源于php中文网

原创

asyncio.timeout() 是上下文管理器而非超时参数,须用 async with 包裹 gather() 或 wait();超时触发时自动取消未完成任务,但要求协程支持取消,否则无法强制终止。

asyncio.timeout() 在 3.11+ 如何与 gather/wait 配合使用

asyncio.timeout() 不能直接传给 gather() 或 wait()

它不是超时参数,而是上下文管理器或异步生成器。常见错误是写成 asyncio.gather(..., timeout=asyncio.timeout(5)) —— 这会报 TypeError: gather() got an unexpected keyword argument 'timeout'。正确做法是把 gather()wait() 整个包进 asyncio.timeout()作用域里。

用 async with asyncio.timeout() 包裹 gather()

这是最直观、推荐的组合方式。超时触发时,所有正在运行的子协程会被取消(前提是它们能响应取消):

async def fetch_user(user_id):
    await asyncio.sleep(2)
    return f"user_{user_id}"

async def main(): try: async with asyncio.timeout(3): results = await asyncio.gather( fetch_user(1), fetch_user(2), fetch_user(3) ) print(results) except asyncio.TimeoutError: print("至少一个任务超时了,整个 gather 被中断")

  • asyncio.timeout() 在超时时刻抛出 asyncio.TimeoutError,并自动调用 cancel() 所有未完成的 Task
  • gather() 包裹的协程必须支持取消(比如不阻塞在纯同步 I/O 或没做 shield()
  • 如果某个子协程内部已处理了 CancelledError 且没重新抛出,gather() 可能不会立即失败,但超时上下文仍会退出

wait() 配合 timeout() 时要注意 done/pending 分离

asyncio.wait() 返回 (done, pending),而 asyncio.timeout() 不改变这个行为。你得手动检查 pending 是否非空:

易可图
易可图

电商人都在用的设计平台

下载
tasks = [asyncio.create_task(fetch_user(i)) for i in range(3)]
try:
    async with asyncio.timeout(2.5):
        done, pending = await asyncio.wait(tasks, return_when=asyncio.FIRST_COMPLETED)
    # 此时 pending 可能还有未完成的任务
    for t in pending:
        t.cancel()
except asyncio.TimeoutError:
    # 所有剩余 task 已被 cancel,但需 await 它们以清理状态
    await asyncio.gather(*pending, return_exceptions=True)
  • wait()return_when 参数决定何时返回,timeout() 只控制整体等待上限
  • pending 中的 task 不会自动 await,必须显式 cancel() + await gather(..., return_exceptions=True) 避免 “task was destroyed but it is pending!” 警告
  • 若用 return_when=asyncio.ALL_COMPLETEDpending 为空,但超时仍会提前跳出

嵌套 timeout() 或与 shield() 冲突要小心

如果你在子协程里也用了 asyncio.timeout(),外层超时会优先触发并取消内层;而 asyncio.shield() 会让被保护的协程忽略外层取消 —— 这可能导致 gather() 卡住或超时不生效:

  • 避免对单个子任务用 shield() 后再丢进带 timeout()gather()
  • 想给不同任务设不同超时?别嵌套 timeout(),改用 wait_for(task, timeout=...) 单独包装每个任务,再 gather() 这些 wait_for() 调用
  • wait_for()timeout() 不兼容混用:前者返回值,后者是上下文;混用容易漏掉取消传播

真正难处理的是那些不响应取消的协程(比如调用了阻塞的 time.sleep() 或没加 await 的 CPU 密集循环),这种情况下 timeout() 无法强制终止,只能等它自己结束。

相关专题

更多
c++ 根号
c++ 根号

本专题整合了c++根号相关教程,阅读专题下面的文章了解更多详细内容。

57

2026.01.23

c++空格相关教程合集
c++空格相关教程合集

本专题整合了c++空格相关教程,阅读专题下面的文章了解更多详细内容。

57

2026.01.23

yy漫画官方登录入口地址合集
yy漫画官方登录入口地址合集

本专题整合了yy漫画入口相关合集,阅读专题下面的文章了解更多详细内容。

237

2026.01.23

漫蛙最新入口地址汇总2026
漫蛙最新入口地址汇总2026

本专题整合了漫蛙最新入口地址大全,阅读专题下面的文章了解更多详细内容。

393

2026.01.23

C++ 高级模板编程与元编程
C++ 高级模板编程与元编程

本专题深入讲解 C++ 中的高级模板编程与元编程技术,涵盖模板特化、SFINAE、模板递归、类型萃取、编译时常量与计算、C++17 的折叠表达式与变长模板参数等。通过多个实际示例,帮助开发者掌握 如何利用 C++ 模板机制编写高效、可扩展的通用代码,并提升代码的灵活性与性能。

17

2026.01.23

php远程文件教程合集
php远程文件教程合集

本专题整合了php远程文件相关教程,阅读专题下面的文章了解更多详细内容。

103

2026.01.22

PHP后端开发相关内容汇总
PHP后端开发相关内容汇总

本专题整合了PHP后端开发相关内容,阅读专题下面的文章了解更多详细内容。

73

2026.01.22

php会话教程合集
php会话教程合集

本专题整合了php会话教程相关合集,阅读专题下面的文章了解更多详细内容。

81

2026.01.22

宝塔PHP8.4相关教程汇总
宝塔PHP8.4相关教程汇总

本专题整合了宝塔PHP8.4相关教程,阅读专题下面的文章了解更多详细内容。

70

2026.01.22

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Go 教程
Go 教程

共32课时 | 4.2万人学习

Go语言实战之 GraphQL
Go语言实战之 GraphQL

共10课时 | 0.8万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号