Tasks and Futures
大多数的工作只涉及到Task、create_task()方法,就像前面代码一样,Future是Task的父类,提供与loop交互的所有功能。
Future对象表示某个活动的未来完成状态,由loop管理,Task与之完全相同,但其活动特指coroutine。Future表示与loop交互的状态,Future对象描述的是完成状态的切换,其实例创建时状态是“尚未完成”,然后在稍后的一段时间后,实例状态为完成,Future的实例有一个done()
方法用于检查状态。
>>> from asyncio import Future>>> f = Future()>>> f.done()False
Future实例可能:
- 有一个结果集(
set_result(value)
、result()
); - 可用
cancel()
取消(通过cancelled()
检查); - 拥有回调函数,并在完成时执行。
即使Task更普遍,但Future仍然无法避免,例如在executor中运行一个函数会返回一个Future对象而非Task。
>>> async def main(f: asyncio.Future): # 1... await asyncio.sleep(1)... f.set_result('I have finished') # 2>>> loop = asyncio.get_event_loop()>>> fut = asyncio.Future() # 3>>> print(fut.done()) # 4False>>> loop.create_task(main(fut)) # 5:1>>>>> loop.run_until_complete(fut) # 6'I have finished'>>> print(fut.done())True>>> print(fut.result()) # 7I have finished
- 创建一个简单的主函数;
- 为Future对象设置结果;
- 手动创建一个Future对象,该对象默认绑定在当前loop上,不能也不会属于任何coroutine;
- 在做任何事之前,先确认Future对象完成状态;
- 调度主程序,并将Future对象传递进去,主程序只是sleep,然后切换到Future对象,并且此时loop还未启动;
- 这里与以前不同的是,用Future对象而不是Task对象,现在loop开始运行;
- Future在设置结果时完成,然后可以访问结果。
绝大多数代码都不会像上面一样直接用Future对象,这里仅作学习用。
用create_task
还是ensure_future
?
后者很容易造成误解,从官方的函数docstring看:
asyncio.ensure_future(coro_or_future, *, loop=None)
Schedule the execution of a coroutine object: wrap it in a future. Return a Task object. If the argument is a Future, it is returned directly.
清楚的解释一下:
1. 如果传入一个coroutine,它将返回一个Task(coroutine将会在loop中调度),这与直接调用create_task()没区别; 2. 如果传入一个Future,直接返回,完全没有改变地!import asyncioasync def f(): # 1 passcoro = f() # 2loop = asyncio.get_event_loop() # 3task = loop.create_task(coro) # 4assert isinstance(task, asyncio.Task) # 5new_task = asyncio.ensure_future(coro) # 6assert isinstance(new_task, asyncio.Task)mystery_meat = asyncio.ensure_future(task) # 7assert mystery_meat is task # 8
- 一个coroutine function;
- 获得coroutine;
- 获得loop;
- 通过create_task调度coroutine;
- 类型检查;
- 与create_task相同;
- Task是Future的子类,这里直接传入一个已经创建好的Task实例;
- 结果是True,完全没区别。
实际上,ensure_future()
是提供给框架开发者处理两种参数用的。
在3.7中,asyncio提供了asyncio.create_task(coro)
方法来为运行中的loop添加task,ensure_future()
可以失业了。