一批任务用 as_completed 收集结果,打印出来的顺序和提交顺序完全不同,代码按列表下标回填,数据整体错位,对账时全乱。乍看像缓存或者权限的锅,追下去往往不是。
async def one(u):
return u, await fetch(u)
for coro in asyncio.as_completed([one(u) for u in urls]):
url, data = await coro
追下去是这么回事:as_completed 按完成先后产出结果,本身不保留提交顺序,用下标去对应原始列表等于假设了两者顺序一致,实际完全靠运气,错位很难发现。
「as_completed 结果对应」这类改动最怕改一半,回滚脚本先准备好,再动生产。验证用真实数据走一遍,测试数据太干净,边界情况根本碰不到。
能分两步做的操作就别合成一步,中间看一眼返回值,出问题好判断。报错里带路径的,先去看那个路径在不在、权限对不对。
具体做法是,提交时把任务标识塞进协程的返回值里,和结果一起带回来;用字典按标识收集结果,别依赖任务产出的先后顺序;确实需要按顺序处理就用 gather,代价是要等最慢那个任务。
验收就看一点,每条结果都带着自己的 url,回填后与原列表一一对应,不会再错位。
