asyncio.create_task
和 asyncio.ensure_future
在Python异步编程中,asyncio
库提供了丰富的工具来处理并发任务。两个常用的方法——asyncio.create_task
和asyncio.ensure_future
——常常让开发者感到困惑,特别是在它们的用法和适用场景上。这篇博客将深入探讨这两个方法,帮助你更好地理解它们之间的区别。
1. 简介:异步编程和事件循环
在开始讨论这两个方法之前,先简单回顾一下异步编程的背景。异步编程的核心概念是事件循环(Event Loop),它通过非阻塞的方式管理多个任务。在asyncio
中,异步函数通常定义为async def
,并通过await
关键字来等待异步操作完成。
2. asyncio.create_task
简介
asyncio.create_task(coro)
用于创建一个异步任务,并将其调度到事件循环中执行。它是Python 3.7中引入的一个函数,专门用于启动异步任务。
用法示例:
import asyncio
async def my_coroutine():
await asyncio.sleep(1)
print("Task complete")
async def main():
task = asyncio.create_task(my_coroutine())
await task
asyncio.run(main())
在上面的代码中,create_task
会立即调度my_coroutine
的执行,而不会阻塞后续代码的执行。
3. asyncio.ensure_future
简介
asyncio.ensure_future
是一个更通用的工具,它可以将一个协程或一个Future
对象封装为一个任务。这个方法在Python 3.4版本中引入,在更早的版本中应用广泛。ensure_future
的一个关键特性是它能保证任务会被调度并执行,即使没有显式地await
它。
用法示例:
import asyncio
async def my_coroutine():
await asyncio.sleep(1)
print("Task complete")
async def main():
task = asyncio.ensure_future(my_coroutine())
# 注意这里没有await
await asyncio.sleep(2)
asyncio.run(main())
在这个例子中,即使我们没有await
task
,my_coroutine
依然会被执行。ensure_future
确保了这个任务会在未来的某个时间点被调度和执行。
4. create_task
vs ensure_future
:细微差别
4.1 协程和Future对象
create_task
只能接受协程作为参数,并返回一个Task
对象。ensure_future
则更加通用,它既可以接受协程,也可以接受一个已经存在的Future
对象。
4.2 任务调度的保证
ensure_future
的一个重要特性是它可以确保即使任务没有被显式地await
,它依然会被调度和执行。相比之下,create_task
更明确地表示你希望立即创建并启动一个新任务,并通常会在稍后使用await
来等待它的完成。
4.3 代码可读性
在语义上,create_task
更直观,明确表示你正在创建并调度一个新的任务。而ensure_future
的名字更为通用,虽然它在保证任务调度方面更强大,但也可能导致混淆,尤其是对于新手而言。
5. 何时使用哪一个?
-
使用
create_task
:当你明确知道自己是在创建一个新的任务,并且希望立即调度它时,create_task
是最佳选择。它在代码中表达意图更加清晰,并且限制了传递非协程对象的可能性。 -
使用
ensure_future
:当你不确定传递的对象是协程还是Future
,或者需要确保任务会在未来某个时间点被执行(即使没有显式await
),ensure_future
是更好的选择。
6. 结论
asyncio.create_task
和asyncio.ensure_future
都是强大的工具,用于异步任务的管理。理解它们之间的细微差别,特别是在任务调度的保证方面,能够帮助你在编写异步代码时做出更好的选择。Python 3.7之后,create_task
成为了首选,因为它语义更清晰,专注于创建任务,而ensure_future
则保留了其通用性和在某些场景下的特殊优势。