python中的未来函数 python未来方向( 五 )


之后再学怎么分析 。
在Python中使用Asyncio系统(3-4)Task 和 FutureTask 和 Future
前面我们讨论了协程 , 以及如何在循环中运行它们才有用 。现在我想简单谈谈Task和Future api 。你将使用最多的是Task,因为你的大部分工作将涉及使用create_task()函数运行协程,就像在第22页的“快速开始”中设置的那样 。Future类实际上是Task的超类,它提供了与循环交互操作的所有功能 。
可以这样简单地理解:Future表示某个活动的未来完成状态,并由循环管理 。Task是完全相同的,但是具体的“activity”是一个协程——可能是你用async def函数加上create_task()创建的协程 。
Future类表示与循环交互的某个东西的状态 。这个描述太模糊了 , 不太有用,所以你可以将Future实例视为一个切换器,一个完成状态的切换器 。当创建Future实例时,切换设置为“尚未完成”状态 , 但稍后它将是“完成”状态 。事实上,Future实例有一个名为done()的方法,它允许你检查状态,如示例 3-15所示 。
示例 3-15. 用done()方法检查完成状态
Future实例还可以执行以下操作:
? 设置一个result值(用.set_result(value)设置值并且使用 .result()获取值)
? 使用.cancel()方法取消 (并且会用使用.cancelled()检查是否取消)
? 增加一个Future完成时回调的函数
即使Task更常见,也不可能完全避免使用Future:例如,在执行器上运行函数将返回Future实例,而不是Task 。让我们快速看一下 示例 3-16 ,了解一下直接使用Future实例是什么感觉 。
示例 3-16. 与Future实例的交互
(L3)创建一个简单的 main函数 。我们运行这个函数,等上一会儿然后在Future f上设置一个结果 。
(L5)设置一个结果 。
(L8)手动创建一个Future实例 。注意,这个实例(默认情况下)绑定到我们的循环,但它没有也不会被附加到任何协程(这就是Tasks的作用) 。
(L9)在做任何事情之前,确认future还没有完成 。
(L11)安排main()协程,传递future 。请记住 , main()协程所做的所有工作就是sleep,然后切换Future实例 。(注意main()协程还不会开始运行:协程只在事件循环运行时才开始运行 。)
(L13)在这里我们在Future实例上而不是Task实例上使用run_until_complete() 。这和你以前见过的不一样 。现在循环正在运行,main()协程将开始执行.
(L16)最终,当future的结果被设置时,它就完成了 。完成后 , 可以访问结果 。
当然,你不太可能以这里所示的方式直接使用Future;代码示例仅用于教育目的 。你与asynccio的大部分联系都是通过Task实例进行的 。
你可能想知道如果在Task实例上调用set_result()会发生什么 。在Python 3.8之前可以这样做,但现在不允许这么做了 。任务实例是协程对象的包装器,它们的结果值只能在内部设置为底层协程函数的结果,如 示例 3-17所示那样 。
示例 3-17. 在task上调用set_result
(L13)唯一的区别是我们创建的是Task实例而不是Future实例 。当然,Task API要求我们提供一个协程;这里我们使用sleep()只是因为简单方便 。
(L7)正在传入一个Task实例 。它满足函数的类型签名(因为Task是Future的子类),但从Python 3.8开始 , 我们不再允许在Task上调用set_result():尝试这样做将引发RuntimeError 。这个想法是,一个Task代表一个正在运行的协程,所以结果应该总是来自于task自身 。
(L10, L24)但是,我们仍然可以cancel()一个任务,它将在底层协程中引发CancelledError 。
Create_task? Ensure_Future? 下定决心吧!
在第22页的“快速入门”中 , 我说过运行协程的方法是使用asyncio.create_task() 。在引入该函数之前,有必要获取一个循环实例并使用loop.create_task()完成相同的任务 。事实上,这也可以通过一个不同的模块级函数来实现:asyncio.ensure_future() 。一些开发人员推荐create_task(),而其他人推荐ensure_future() 。

推荐阅读