asyncio.ensure_future() 用于调度协程(coroutine)或其他可等待对象(awaitable)的执行。它的核心功能是确保一个可等待对象最终被包装成一个 asyncio.Task 对象,并安排它在事件循环中运行。
asyncio.ensure_future 的主要作用
调度执行:当你有一个协程函数,但不想立即
await它(因为await会阻塞当前任务直到该协程完成),你可以使用asyncio.ensure_future()来把它提交给事件循环,让它在后台并发执行。统一对象类型:这个函数非常灵活,它可以接受多种类型的输入:
- 如果是协程(coroutine):它会调用
loop.create_task()将协程包装成一个Task对象。 这个Task会被安排在事件循环中执行。 - 如果是
Future或Task对象:它会直接返回该对象,不做任何改变。 因为Task本身就是Future的子类。 - 如果是其他可等待对象(awaitable):它会将其包装在一个
Task中,该任务会await这个对象。
这个特性使得
ensure_future()在编写库或API时特别有用,因为你无需关心传入的到底是一个协程还是一个已经存在的Task,ensure_future()都能确保你得到一个可以操作的Future对象(比如用于取消操作)。- 如果是协程(coroutine):它会调用
asyncio.ensure_future vs asyncio.create_task
在现代 Python (3.7+) 中,asyncio.create_task() 是创建和调度任务的首选方式。 了解它们之间的区别很重要:
asyncio.create_task(coro):- 目的明确:专门用于从一个协程创建并调度一个
Task。 它是更高级别的API,推荐在应用代码中使用。 - 输入限制:它的参数只能是协程对象。
- 可读性好:函数名清晰地表达了其意图——创建一个任务。
- 目的明确:专门用于从一个协程创建并调度一个
asyncio.ensure_future(awaitable):- 功能更广泛:如上所述,它可以接受协程、
Future、Task或其他可等待对象。 - 向后兼容:
create_task()是在 Python 3.7 中引入的。在之前的版本中,ensure_future()是创建任务的主要方式。 - 适用场景:当你需要编写一个能同时处理协程和
Future对象的通用函数时,ensure_future()更加合适。
- 功能更广泛:如上所述,它可以接受协程、
总结:在 Python 3.7 及更高版本中,如果你明确知道要从一个协程创建一个任务,应该优先使用 asyncio.create_task()。 只有在需要兼容旧版本或处理不确定是协程还是 Future 的输入时,才需要使用 asyncio.ensure_future()。
如何使用 asyncio.ensure_future
下面是一个代码示例,展示了如何使用 ensure_future() 来并发执行任务。
1 | import asyncio |
运行结果分析:
main函数开始执行,task1和task2通过asyncio.ensure_future()被调度。它们会立即开始并发运行,而不是一个接一个。- 程序打印 “任务已调度…”,并等待1秒。在此期间,
task1和task2都在后台执行它们的asyncio.sleep()。 await task1和await task2会等待各自的任务完成。由于它们是并发执行的,总耗时取决于最长的那个任务(任务B,3秒),而不是两个任务时间的总和(2 + 3 = 5秒)。- 最终的总耗时约等于3秒,证明了并发执行的效率。
- 示例也验证了当
ensure_future的参数已经是Task时,它会返回完全相同的对象。