问题
几天来,我无法理解 Future 和 Task 对象之间的区别。更准确地说,我不确定我是否完全理解使用的内容和位置。
我的理解
从文档中可以看出,在 asyncio 中有三种类型的 curutin 对象,任务(Task)和期货(Future)(我们称之为)。任务是计划在事件循环中运行的curout。
当协程被包装到具有 asyncio.create_task() 之类的函数的任务中时,协程会自动安排为很快运行
期货是某种存储异步操作可能结果的对象。
Future 表示异步操作的最终结果
那些。为了启动 curutina 以异步模式执行,您需要使用asyncio.create_task,但是为什么我们需要ensure_future呢?它出现在所有 asyncio 代码示例中。我在 stackoverflow 上找到了一个相关问题,但在我看来,那里没有正常的答案。下面是我使用不同选项启动 curutin 的代码 - 结果总是相同的:
import asyncio
import time
async def fetch(n):
await asyncio.sleep(n)
print(time.time())
return n
loop = asyncio.get_event_loop()
# coros = [asyncio.ensure_future(fetch(i)) for i in range(2)]
# coros = [fetch(i) for i in range(3)]
coros = [loop.create_task(fetch(i)) for i in range(2)]
results = loop.run_until_complete(asyncio.gather(*coros))
print(results)
使用选项 2 和 3,这是可以理解的,因为根据文档,gather 将 curutins 转换为任务,但他们为什么使用ensure_future. 该文档还说最好使用create_task.
另请参阅 create_task() 函数,它是创建新任务的首选方式。
总而言之,我想听听关于未来是什么、它与任务有何不同以及在何处使用它的简单解释。
目前尚不完全清楚究竟是什么不清楚,所以我会尽量简化答案,同时诉诸粗略的假设。愿我的同事们原谅我。
协程是调用一个异步函数的结果,也就是这个函数的执行可以被挂起。由于在一般情况下无法确定执行将暂停多少次和多长时间,因此也无法确定何时完成。您的代码可以等待协程完成语句
await,或者将等待留给事件循环并继续执行。在第一种情况下
执行
caller将暂停,直到callee. 此时,其他一些协程中的一些其他操作可能会继续,但caller会等待它执行的地方await。在第二种情况下
caller立即继续工作。字符串“World”将在“Hello”之前打印。在这里我们看到我们caller设置了事件循环来执行协程callee。但是如果
callee它返回调用者需要的一些值,但不是现在,而是当它准备好时呢?这就是期货发挥作用的地方。Futura(未来)——协程执行的未来结果。该方法
ensure_future指示事件循环执行协程,并在调用时立即返回值将在其中的未来,但不知道何时。调用者可以像等待协程本身一样等待未来的执行或者他可以开展他的业务,定期检查准备情况
或者在未来安装回调
或者也许将它们收集在一个列表中并等待一切。或者不是全部,而只是将首先执行的一个,而忽略其余的。或者将未来传递给另一个协程,然后自己做其他事情。总的来说,它是“一个非常有用的锅,你可以放任何你想要的东西”。
剩下的只是弄清楚未来与任务有何不同。在大多数情况下,它们没有什么不同。Task类是Future类的后代。
asyncio.create_task()和之间唯一显着的区别loop.ensure_future()是第一个在 Python 3.7 之前不存在。总结一下:
Task是分配给事件循环的一个任务,要执行coroutine,也是一个Future,是Task未来某个时间执行的结果。