Python中篇 3. asyncio中协称如何被事件循环调度的-Future/Task是关键先生

简介: Python中篇 3. asyncio中协称如何被事件循环调度的-Future/Task是关键先生

1. 前言



大家比较好奇,我们讲了那么多的协称和事件循环知识,为啥一直没有提到事件循环如何调度协称的呢?不好意思哈,我想把大家的好奇心留在这一篇文章中,接下来我希望你们拿好板凳,带上瓜子和水,用眼睛往下瞅。


我们接下来了解两个概念,在说说协称如何被调度


2. Future对象



asyncio中,如何才能得到异步调用的结果呢?先设计一个对象,异步调用执行完的时候,就把结果放在它里面,这种对象称之为未来对象。未来对象有一个result方法,可以获取未来对象的内部结果。还有个set_result方法,是用于设置result的。set_result设置的是什么,调用result得到的就是什么。Future对象可以看作下面的Task对象的容器。


3. Task对象



一个协程就是一个原生可以挂起的函数,Task则是对象协程的进一步封装,里面可以包含协程在执行时的各种状态,关于TaskFuture两者之前的关系我们后面会说。


4. Task和Future与协程的关系



TaskFuture的派生类,它有一个核心step方法,这个方法和协称调度有关,但是这个方法只有Task独有,Future是没有的,但是Futureset_result方法,这个方法可以被FutureTask共同调用。同时TaskFuture和协称之间的桥梁,因为Task执行结束的时候会调用Futureset_result方法,这样Future通过result方法就会知道协称运行的结果,所以说Future想要知道协称的运行结果,那么必须将协称绑定Task,这样Task才能把结果设置到Future中。


5. 协称如何被事件循环调度



对于协程来说,是没有办法直接放到事件循环里面运行的,需要Task对象(任务)。而我们之前直接将协程扔进loop中是因为asyncio内部会有检测机制,如果是协程的话,会自动将协程包装成一个Task对象。例如:


import asyncio
async def coroutine():
    print("hello world")
if __name__ == "__main__":
    loop = asyncio.get_event_loop()
    # 如何创建一个任务呢?
    task = loop.create_task(coroutine())
    loop.run_until_complete(task)
运行结果:
"""
hello world
"""


事件循环怎么调度协称的呢?


loop通过create_task(coroutine())创建task,入参是协称,task在初始化的时候会调用:loop.call_soon(self._step),然后call_soon会在loop的_ready回调队列中添加一个Handle实例,最后为task对象添加一个done callback来停止loop。

task初始化完成,我们运行loop.run_until_complete(task)最终会调用loop.run_forever()

loop.run_forever()本质是一个while循环,只要loop没有被标记为停止,就会反复调用self._run_once(),在_run_once()中,loop会将_ready回调队列中所有的Handle实例依次取出并执行,这里就执行到了前面task实例的_step()

_step方法会执行两个重要操作,第一个就是启动协称的运行,通过调用协称的send(None)方法启动。第二个就是协称运行完毕会抛出StopIteration异常,而这个异常里面的value就是协称返回的值,把这个value通过Futureset_result方法设置进去,这样我们的Task或者Future就会通过Result获取返回值,即协称的返回值。我们通常在代码中等待协称返回都是如下这种方式:

result = await future //相当于调用Future.Result()方法
result = await task //同上

这样我们就可以拿到协称的返回值,而事件循环会继续在_ready队列中查找有没有其他的待运行Handler实例。


参考:https://segmentfault.com/q/1010000016451903


6. 小结



总结一下核心重点:TaskFuture和协称之间的桥梁,而协称的调度离不开事件循环,事件循环又通过Task生成Handler实例,最终被事件循环调度,所以说asyncio复杂背后的设计逻辑是环环相扣的,只有把相关概念和原理吃透,你才能彻底掌握他们。

相关文章
|
2月前
|
机器学习/深度学习 算法 调度
基于多动作深度强化学习的柔性车间调度研究(Python代码实现)
基于多动作深度强化学习的柔性车间调度研究(Python代码实现)
150 1
|
2月前
|
数据采集 数据库 开发者
利用Python asyncio实现高效异步编程
利用Python asyncio实现高效异步编程
225 100
|
3月前
|
调度 Python
微电网两阶段鲁棒优化经济调度方法(Python代码实现)
微电网两阶段鲁棒优化经济调度方法(Python代码实现)
|
3月前
|
供应链 新能源 调度
微电网调度(风、光、储能、电网交互)(Matlab&Python代码实现)
微电网调度(风、光、储能、电网交互)(Matlab&Python代码实现)
|
2月前
|
调度 数据库 Python
Python异步编程入门:asyncio让并发变得更简单
Python异步编程入门:asyncio让并发变得更简单
165 5
|
8月前
|
移动开发 JavaScript 前端开发
精通服务器推送事件(SSE)与 Python 和 Go 实现实时数据流 🚀
服务器推送事件(SSE)是HTML5规范的一部分,允许服务器通过HTTP向客户端实时推送更新。相比WebSocket,SSE更轻量、简单,适合单向通信场景,如实时股票更新或聊天消息。它基于HTTP协议,使用`EventSource` API实现客户端监听,支持自动重连和事件追踪。虽然存在单向通信与连接数限制,但其高效性使其成为许多轻量级实时应用的理想选择。文中提供了Python和Go语言的服务器实现示例,以及HTML/JavaScript的客户端代码,帮助开发者快速集成SSE功能,提升用户体验。
|
3月前
|
传感器 数据采集 监控
Python生成器与迭代器:从内存优化到协程调度的深度实践
简介:本文深入解析Python迭代器与生成器的原理及应用,涵盖内存优化技巧、底层协议实现、生成器通信机制及异步编程场景。通过实例讲解如何高效处理大文件、构建数据流水线,并对比不同迭代方式的性能特点,助你编写低内存、高效率的Python代码。
183 0
|
2月前
|
算法 定位技术 调度
基于蚂蚁优化算法的柔性车间调度研究(Python代码实现)
基于蚂蚁优化算法的柔性车间调度研究(Python代码实现)
134 0
|
3月前
|
运维 算法 新能源
基于风光储能和需求响应的微电网日前经济调度(Python代码实现)
基于风光储能和需求响应的微电网日前经济调度(Python代码实现)
102 0

推荐镜像

更多