asyncio.cancel() 是中断异步下载最直接有效的方式,它通过抛出 asyncio.CancelledError 实现协作式取消,需在 try/except 中清理资源、避免阻塞调用、分块读取响应并 await task 确保取消生效。

asyncio.cancel() 是中断异步下载最直接有效的方式
只要任务是通过 asyncio.create_task() 或 asyncio.ensure_future() 启动的,且没有被 await 阻塞在不可取消点(比如某些底层 I/O),调用 task.cancel() 就能触发取消逻辑。关键在于:它不会“强行杀掉”协程,而是抛出 asyncio.CancelledError,由你控制如何清理资源。
常见错误现象是调用 cancel() 后下载仍在后台继续——这通常是因为:任务正在执行一个未检查取消状态的阻塞式调用(如 time.sleep())、或用了不支持取消的第三方库函数(如某些同步 HTTP 客户端包装层)、或没 await 该 task 导致取消信号根本没机会传播。
- 务必在
try/except CancelledError块中做清理,比如关闭aiohttp.ClientSession、删除已写入的临时文件 - 避免在协程里用
time.sleep();改用await asyncio.sleep(),它可被取消 - 如果使用
aiohttp,确保用session.get(url, timeout=...)显式设置超时,否则 DNS 解析或连接卡住时 cancel 可能延迟生效
用 asyncio.wait_for() 包裹下载协程可实现带超时的可控中断
asyncio.wait_for() 不仅能设超时,本质也是基于 cancel() 实现的——它会在超时后自动取消目标协程。但要注意:它只对顶层协程生效,若你把整个下载逻辑封装在一个函数里并传给 wait_for,那取消信号会正确冒泡到内部 await 点。
使用场景包括:用户点击“取消下载”按钮、或后台任务需限制单次下载耗时不超过 30 秒。
- 不要对已 await 完成的协程再套
wait_for,会报InvalidStateError - timeout 参数建议用
asyncio.Timeout对象(Python 3.11+)或浮点数;传None表示无超时,失去中断能力 - 捕获
asyncio.TimeoutError后,仍需手动处理残留资源(如未关闭的响应 body 流)
aiohttp.ClientResponse.content.read() 必须配合异常处理才能响应取消
这是实际开发中最容易踩的坑:response.content.read() 返回的是一个可 await 的迭代器,但它本身不主动检查取消状态。如果你写 data = await response.content.read(),而此时 task 已被 cancel,协程会挂起直到读完或连接断开,导致取消失效。
让 macOS 自动化像说话一样简单 —— 用代码控制你的 Mac,无需学习 AppleScript 系统要求 macOS 14+ (Sonoma) Python 3.9+ 需要开启:辅助功能 + 屏幕录制权限
正确做法是分块读取,并在每次 await 前确认任务是否被取消。
while not task.cancelled():
chunk = await response.content.read(8192)
if not chunk:
break
# 写入文件或处理数据
或者更稳妥地,在循环内加 if task.cancelled(): break,并在 finally 块中关闭 response。
取消后 await task 本身可能引发 CancelledError,必须显式处理
调用 task.cancel() 只是标记任务为“待取消”,真正抛出 CancelledError 是在下一次 await task 时。如果你忽略这一步,就无法知道取消是否完成、也无法做后续清理。
- 永远不要只调用
task.cancel()就结束;应紧接着await task或await asyncio.shield(task)(若想抑制取消) - 若在取消后仍需等待其他任务,可用
asyncio.gather(task, other_task, return_exceptions=True)避免因一个任务取消导致整个 gather 失败 - 注意:
task.done()为 True 不代表已清理完毕——它只表示协程已退出(无论正常还是被取消)
真正难的不是调用 cancel(),而是确保每个 await 点都尊重取消信号,尤其是第三方库的 API 是否真正可取消。很多“中断失败”的问题,根源都在底层 HTTP 客户端或流式解析器没透出 cancellation hook。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










