Agent 应用开发会员账号
知识目录选择核心方向与细分内容
知识单元 14高级实现约 18 分钟

理解 → 实现 → 排错 → 取舍

并行结果的交付条件与共享截止时间

考察异步并发、截止时间、取消传播与部分结果。

asyncio并发Deadline

知识内容核对 2026-10-03 · 原题来源核对 2026-10-02

这个知识点,你想学到哪一步?

按当前基础选择起点,也可以依次深入。遇到不熟悉的概念,先回到核心原理;完成后用知识练习检查理解。

先理解

刚接触这个知识点

补齐先备概念,读原理与反例,再用自己的话解释为什么。

从核心原理开始 →

再实现

准备把原理写进代码

理解实现步骤与边界,完成小任务,对照验收要求检查结果。

查看代码示例 →

会排错

需要处理故障与条件变化

沿连续追问定位失效前提,再比较迁移案例,说明方案应如何调整。

沿问题继续深入 →

能取舍

需要设计或评审方案

结合工程推演与资深自评标准,解释方案的适用条件、代价和替代选择。

分析工程场景 →
知识单元目录

LEARN · PRACTICE · REFLECT

知识学习与个人记录

我的笔记与复习 ↗

先沿着原理、问答和迁移案例阅读。需要检查理解时,再切换巩固练习或展开个人记录。

作答与个人记录

每次修改后的提交会保留为独立历史。掌握程度由你对照标准自评。

核心知识 · 并行结果的交付条件与共享截止时间

先理解核心原理

先备概念:事件循环、结构化并发、请求超时

并行只缩短独立等待,不改变任务依赖与成功条件。全局截止时间约束全部尝试与退避;一个本地任务被取消,也不证明远端副作用停止,结果必须逐项保留并分类。

先定义结果怎样算完成

三个独立新闻查询可以返回缺一个地区的部分结果,三个发布前校验则可能必须全部通过。required 属性在任务开始时定义;错误发生后临时把失败项降成可选,会制造虚假的成功。依赖另一个工具输出的调用不能同时启动。

异步的关键是释放执行权

async 只是函数声明,里面直接调用阻塞 HTTP 仍会阻塞事件循环,让其他工具、超时和取消不能及时调度。使用真正异步 I/O,无法改动的阻塞调用放到受控线程或进程,并设置底层超时。线程中的操作未必能随协程取消。

并发原语有不同语义

Python gather 默认首个异常传播后,其他任务继续;TaskGroup 的失败会取消同组其他任务并等待清理。选哪种取决于全部成功或部分结果策略,不能以 API 名字猜行为。共享 deadline 用单调时钟计算,重试、排队与退避都消耗剩余时间。

用一个问题检查理解

三个工具并行调用,一个很慢、一个失败,如何返回结果?

先按依赖决定哪些可并行,再明确是必须全部成功还是允许部分成功。为整个任务设截止时间,并给每个工具分配剩余时间和并发额度。独立只读任务可保留成功结果;有依赖或写副作用的操作需要更严格的协调。取消本地等待不代表远端操作没发生,结果应分别标记成功、失败、超时未知和取消。

实现与取舍

并发结构由交付条件决定

如果三个工具分别获取三个地区的新闻,可以接受带缺口的部分结果;若它们共同构成一次发布前校验,任何关键校验失败都应阻止发布。把 required 标记放进任务定义,不在异常发生后临时决定算不算成功。依赖另一个工具输出的调用必须等到输入已验证,不能为了速度硬并行。

共享截止时间与容量

任务入口计算绝对 deadline,每一步使用剩余时长,不在每次重试重置完整超时。使用并发上限限制同时占用的连接与配额,超时等待也计入预算。异步库的任务组、聚合等待和取消行为不同,应明确选用的语义;同步阻塞函数即使写在 async 函数里也可能阻塞事件循环。

错误和取消如何收口

结果封装为工具 ID、状态、数据、耗时、错误类型和是否需要核对外部动作。独立读任务单个失败不必丢弃所有成功结果;关键任务失败时取消未开始动作。已经发出的写请求进入回执核对,不能把 CancelledError 直接解释为业务取消成功。清理连接和释放并发槽放在确定能执行的清理路径。

现场检查

模拟 A 在 100ms 成功、B 立即失败、C 一直等待,全局截止时间 500ms。验证程序有界退出,A 的有效结果保留,B 错误可见,C 不占用遗留资源。若要求全部成功,最终不得标记 succeeded。进一步让 C 在取消后完成远端写入,检验候选人是否区分本地协程状态和外部事实。

代码示例

保留成功结果并清理超时任务

只读异步任务的最小演示;不保证远端写请求随本地取消而撤销。

import asyncio

async def ok():
    return "result"

async def fail():
    raise RuntimeError("unavailable")

async def slow():
    await asyncio.Event().wait()

async def main():
    tasks = {"a": asyncio.create_task(ok()), "b": asyncio.create_task(fail()),
             "c": asyncio.create_task(slow())}
    done, pending = await asyncio.wait(tasks.values(), timeout=0.02)
    for task in pending:
        task.cancel()
    await asyncio.gather(*pending, return_exceptions=True)
    for name, task in tasks.items():
        if task in pending:
            status = "timeout"
        elif task.exception() is not None:
            status = "failed"
        else:
            status = "succeeded"
        print(name, status)

asyncio.run(main())

预期输出

a succeeded
b failed
c timeout

工程推演

场景
面试假设:研究助手并行查询三种来源,其中一个超时。
设计决策
记录每源状态,使用全局截止时间,按事先定义的最低证据要求验收。
验证目标
返回可验证结果和缺失来源,所有本地等待有界结束。
适用边界
写工具需要额外回执核对,不能直接套用只读取消逻辑。

连续追问与解答

沿着问题的前提和约束继续向下读。先理解参考解答,再尝试收起答案,用自己的话解释因果和取舍。

举一反三:条件变了,怎样推导?

先找出改变的条件,再判断原方案中哪些前提仍成立。下面的案例是教学推演,便于将原理迁移到新问题。

必须全成功的发布校验

改变的条件:独立数据读取变为发布门槛

延伸问题:慢检查超时可以先发布吗?

推导与参考解答

不能。任何 required 检查未通过都阻止发布,保留成功证据与失败原因供修复;新一轮重新检查可能失效的版本。性能优化可调整并发和检查范围,但不能在超时后偷偷修改成功定义。

保持不变的原理:并行不改变依赖与验收。

一项工具负责写入

改变的条件:全部只读变成读写混合

延伸问题:到期后取消所有任务就结束了吗?

推导与参考解答

停止未开始操作,取消可取消等待,已提交写入进入结果核验。成功读结果可保存,但依赖该写结果的总结不能生成确定结论;回执迟到时按操作 ID 更新账本。读写混合需要业务状态与协程状态分开。

保持不变的原理:本地并发状态不是外部业务状态。

易错点

  • 所有调用统一无上限 gather
  • 失败后把其他成功结果丢掉
  • 取消协程就声称远端未执行

参考资料

依据公开技术资料设计;参考资料支持技术机制,场景与评分标准为本站设计,不代表某公司面试原题。 新增问答与迁移案例用于原理讲解,来源核查与案例运行验证分别记录。

检查自己理解到哪一步

读完后可以对照这些标准解释原理、边界和取舍。掌握程度由你自评;需要进一步验证时,再完成下方小任务。

基础达标
能设置并发上限、超时和每工具状态。
中高级信号
能按交付条件选择取消策略并清理资源。
资深信号
解释阻塞、任务组语义与远端未知结果的边界。

查看独立示例的校验记录

动手验证 按需完成 · 建议 15 分钟

写伪代码并行调用三个只读工具,在 500ms 截止时返回逐项状态。

展开验收要求与检查点
  • 最慢任务不无限挂起
  • 成功和失败分别可见
  • 必须全部成功时不能部分冒充完成

重点检查

  • 按依赖和必需性设计并发
  • 共享 deadline 而非重置超时
  • 处理本地取消与远端动作差异