asyncio.create_task()是Python 3.9+创建Task的标准方式,语义清晰、开销更低;ensure_future()因多态逻辑易误用且不推荐用于新代码;create_task()立即调度协程并返回Task,避免悬空协程;loop.create_task()适用于底层控制场景。

asyncio.create_task() 是 Python 3.9+ 创建 Task 的标准方式
Python 3.9 开始,asyncio.create_task() 成为创建并发任务的首选,它直接把协程调度进事件循环,语义清晰、开销更低。此前(3.7–3.8)虽已引入该函数,但官方文档仍常混用 asyncio.ensure_future();而 3.9 后,ensure_future() 的文档明确标注“不推荐用于新代码”,并强调其设计初衷是桥接低层 Future 对象,不是给协程用的。
ensure_future() 的参数逻辑容易误用
asyncio.ensure_future() 会根据传入对象类型做不同处理:协程 → 包装成 Task;Future 或 Task → 直接返回;其他 awaitable → 新建 Task 等待它。这种多态行为看似灵活,实则埋雷:
- 传入普通函数(非协程)会静默失败或抛
TypeError,错误信息不直观 - 传入已取消的
Task时,返回值仍是那个已取消对象,容易让人误以为新建了任务 - 在自定义事件循环或子线程中调用时,
loop参数若未显式指定,可能绑定错循环
而 create_task() 只接受协程对象,类型检查更早、报错更直接。
create_task() 隐含调度时机,避免“悬空协程”陷阱
协程对象本身不执行,必须被调度。常见错误是只调用 main() 得到一个 <coroutine object ...> 就停手,没用 create_task() 或 await 或 run() 触发它。区别在于:
让 macOS 自动化像说话一样简单 —— 用代码控制你的 Mac,无需学习 AppleScript 系统要求 macOS 14+ (Sonoma) Python 3.9+ 需要开启:辅助功能 + 屏幕录制权限
立即学习“Python免费学习笔记(深入)”;
-
create_task(coro)立即把协程注册进当前运行的事件循环,返回可等待的Task实例 -
ensure_future(coro)在无运行循环时可能创建新循环(取决于上下文),行为更不可控 - 如果在
async with或async for块外调用create_task(),但没保存返回值,Task 可能被垃圾回收中断执行——这点和ensure_future()一样,但create_task()的命名更提醒你“要存住它”
3.9+ 的 loop.create_task() 更适合底层控制
当需要显式操作事件循环(比如在库开发或测试 mock 中),loop.create_task() 比全局函数更精确:
- 它强制你持有
loop实例,避免隐式依赖当前运行循环 - 可以配合
loop.set_task_factory()自定义 Task 构造逻辑(如注入 tracing context) - 在多线程场景下,比
asyncio.create_task()更安全——后者内部调用get_running_loop(),若不在协程/回调里调用会直接报RuntimeError
不过绝大多数业务代码不需要碰这个层级,asyncio.create_task() 已足够。

















