必须用:需并发执行i/o协程(如http请求)且不阻塞主流程;不该用:仅顺序等待结果时,直接await更轻量。核心是立即调度协程进事件循环并返回task供控制。

asyncio.create_task 什么时候该用,什么时候不该用?
asyncio.create_task 的核心作用是把一个协程立即调度进事件循环,让它“立刻开始跑”,而不是等你 await 它才执行。但它不是万能加速器——如果你的任务本身是 CPU 密集型(比如计算斐波那契、解析大 JSON),用 create_task 不会变快,反而可能因上下文切换拖慢整体。
常见错误现象:RuntimeWarning: coroutine 'xxx' was never awaited,往往是因为写了 my_coro() 却没 await 或没 create_task,协程对象被丢弃了。
使用场景:
- 多个 I/O 型协程(如 HTTP 请求、数据库查询、文件读写)需要并发启动
- 主逻辑不依赖其结果,但希望它们“后台跑起来”
- 需要提前触发耗时初始化(比如连接池预热、缓存预加载)
注意:在非 running 的 event loop 中调用 create_task 会报 RuntimeError: no running event loop,必须确保已在 asyncio.run() 或 loop.run_until_complete() 内部。
如何避免 create_task 后任务被意外取消或丢失?
create_task 返回一个 Task 对象,它是个强引用——只要变量还活着,任务就不会被 GC。但很多人写成这样:
asyncio.create_task(fetch_data())
这会产生一个“无人认领”的 task,一旦函数返回,task 就失去引用,如果它还没完成,就可能被事件循环在下次循环中清理掉(尤其在程序退出前),导致后台任务静默失败。
正确做法:
- 显式保存 task 引用,比如放进列表或字典
- 在合适时机
await或asyncio.wait_for(task, timeout=...) - 若真不需要结果,至少加个
asyncio.create_task(...).add_done_callback(...)做日志或错误捕获
tasks = [] tasks.append(asyncio.create_task(send_notification())) tasks.append(asyncio.create_task(update_cache())) # 后续可统一 await asyncio.gather(*tasks) 或逐个检查 done()
别忽略异常:未被捕获的 task 异常不会冒泡到主协程,只会打印警告。用 task.exception() 检查是否出错。
视频生成工具。当用户说CreateVideo、创建视频、生成视频或提供文案要求制作视频时触发。支持文本转语音(通过ListenHub MCP)、模板视频裁剪合并、内容分析输出。依赖ffmpeg和ListenHub MCP Server。
create_task 和 asyncio.ensure_future 有什么区别?
asyncio.ensure_future 更底层,能接受协程、future、task 甚至普通可等待对象;create_task 只接受协程对象,且强制绑定当前 loop,语义更清晰、安全性更高。
参数差异:
-
create_task(coro, *, name=None):Python 3.8+ 推荐,name参数便于调试(task.get_name()) -
ensure_future(obj, *, loop=None):loop 不传时自动获取当前 loop,但若当前没有 running loop,行为不如create_task明确
性能影响几乎无差别,但 create_task 在类型检查(如 mypy)和 IDE 支持上更好,也更难误传非协程对象。
容易踩的坑:传入已 await 过的协程(即返回值而非协程对象),会直接报 TypeError: a coroutine was expected, got ...。确认你传的是 my_coro(),不是 await my_coro() 的结果。
为什么有时 create_task 看起来没“加速”?
典型原因不是 create_task 本身问题,而是任务之间存在隐式依赖或共享资源瓶颈:
- 所有 HTTP 请求都走同一个
aiohttp.ClientSession,而 session 默认只开 100 个连接,再多请求会排队 - 文件读写共用一个
open()句柄,实际仍是串行 - 数据库连接池太小,task 被卡在 acquire connection 上
解决思路:
- 查看实际并发数:用
asyncio.current_task().get_coro()+ 日志确认是否真并行 - 把阻塞操作(如
time.sleep()、json.loads())移到loop.run_in_executor() - 调整连接池大小(如
aiohttp.TCPConnector(limit=500))
最常被忽略的一点:create_task 只负责“启动”,不保证“完成”。如果你在 main 协程末尾直接 return,没等 task 结束,它们大概率被 cancel —— 即使你用了 create_task,也得管收尾。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










