结论:两者都并发调度多个协程。gather(*aws) 面向" fork-join":按入参顺序返回结果列表,默认第一个异常立即向外抛出(其余任务继续跑);return_exceptions=True 时异常作为结果占位返回。wait(aws) 面向"完成集合":返回 (done, pending) 两个 task 集合,可用 return_when 控制(FIRST_COMPLETED / FIRST_EXCEPTION / ALL_COMPLETED),不抛子任务异常。

展开:选型:要结果且顺序对应输入、语义简单——gather;要"谁先完成处理谁"(超时竞速、批量进度)——wait。坑位清单:1)gather 默认模式下抛出首异常后其余任务不被取消也不被等待,它们的异常若无人 retrieve 会在 GC 时打 "Task exception was never retrieved" 警告;要全部成功语义常配合 try 包裹或用 TaskGroup(3.11+,推荐,异常时自动取消兄弟任务并以 ExceptionGroup 抛出)。2)wait 返回的是 task 不是结果,要 t.result() 取,且 done 集合无序。3)asyncio.wait_for 超时会取消任务——被取消协程里的 finally/CancelledError 处理要写对,裸 except Exception 吞不掉 CancelledError(3.8 起它继承 BaseException)。

import asyncio

async def main():
    try:
        async with asyncio.TaskGroup() as tg:   # 3.11+ 推荐
            t1 = tg.create_task(job(1))
            t2 = tg.create_task(job(2))
    except* ValueError as eg:                   # ExceptionGroup 解包
        handle(eg)
    results = [t1.result(), t2.result()]

追问方向:TaskGroup 与 gather 的语义差异表、shield 保护任务不被取消的场景与代价。