klippy — reactor模块
- 该模块负责管理事件的注册、调度和处理,充当事件驱动的核心引擎,驱动整个klippy系统的运行。
- 该模块提供了一个统一的接口register_callback,使各个模块能够注册自己的回调函数以响应特定的事件。
- 使用事件循环的方式,不断地检查事件的状态并触发相应的回调函数。
reactor模式
Reactor 模式是一个事件驱动的编程模式,它允许程序以非阻塞的方式处理多个 I/O 操作。这个模式主要包含四个核心组件:
- 事件循环(Event Loop):它负责不断监听事件,并将其分发给相应的处理器。
- 反应堆(Reactor):作为事件循环的管理者,它监视一组资源,等待事件发生。
- 资源(Resources):通常是网络套接字或文件描述符,是反应堆监视的对象。
- 事件处理器(Event Handlers):每个事件都有相应的处理器来响应。

入口
try:
select.poll
Reactor = PollReactor
except:
Reactor = SelectReactor
- 如果支持 select.poll,则调用PollReactor,否则,调用SelectReactor
初始化
class PollReactor(SelectReactor):
def __init__(self, gc_checking=False):
SelectReactor.__init__(self, gc_checking)
self._poll = select.poll()
self._fds = {}
class SelectReactor:
NOW = _NOW
NEVER = _NEVER
def __init__(self, gc_checking=False):
# Main code
self._process = False
self.monotonic = chelper.get_ffi()[1].get_monotonic
# Python garbage collection
self._check_gc = gc_checking
self._last_gc_times = [0., 0., 0.]
# Timers
self._timers = []
self._next_timer = self.NEVER
# Callbacks
self._pipe_fds = None
self._async_queue = queue.Queue()
# File descriptors
self._fds = []
# Greenlets
self._g_dispatch = None
self._greenlets = []
self._all_greenlets = []
- PollReactor 继承自SelectReactor,在初始化的时候,调用SelectReactor初始化,对timers、文件描述符、Greenlets等进行初始化。
def run(self):
if self._pipe_fds is None:
self._setup_async_callbacks()
self._process = True
g_next = ReactorGreenlet(run=self._dispatch_loop)
self._all_greenlets.append(g_next)
g_next.switch()
- run方法 在klippy.py 主循环 打印机对象初始化后,会调用该方法。
- self._process: 设置True 为运行状态。
- ReactorGreenlet(run=self._dispatch_loop):生成协程,进入事件主循环协程。
- g_next.switch():切换到协程g_next。
事件驱动主循环
def _dispatch_loop(self):
self._g_dispatch = g_dispatch = greenlet.getcurrent()
busy = True
eventtime = self.monotonic()
while self._process:
timeout = self._check_timers(eventtime, busy)
busy = False
res = self._poll.poll(int(math.ceil(timeout * 1000.)))
eventtime = self.monotonic()
for fd, event in res:
busy = True
self._fds[fd](eventtime)
if g_dispatch is not self._g_dispatch:
self._end_greenlet(g_dispatch)
eventtime = self.monotonic()
break
self._g_dispatch = None
该方法实现了基于poll函数的事件循环,通过轮询文件描述符上的事件,并根据事件类型调用相应的回调函数进行处理。在处理完一个事件后,如果需要切换到其他协程进行执行,则使用greenlet实现切换。整个过程不断循环,直到_process 为False,则结束事件循环。
- eventtime = self.monotonic():获取当前的时间
- timeout = self._check_timers(eventtime, busy):检查是否有任何定时器事件需要处理。该方法返回下一个定时器事件的超时时间。
- self._poll.poll(int(math.ceil(timeout * 1000.))):轮询操作,等待文件描述符上的事件发生。
- self._fdsfd: 调用文件描述符相应的回调函数。主要监听本地socket文件和一个reactor的双向管道文件描述符。
- if g_dispatch is not self._g_dispatch: 判断当前的greenlet与事件循环的greenlet是否相同,不同则切换协程。
- self._end_greenlet(g_dispatch):结束当前协程,并切换到其他协程。
协程
- greenlet 是python实现协程的一个三方库,是一种基于协作式的多任务编程模型,允许在同一线程内实现多个并发执行的任务。
- greenlet 是协作和顺序的。当一个 greenlet 运行时,其他 greenlet 都不能运行;开发者可以完全控制何时在 greenlet 之间切换执行。
- 协作式调度: 协程通常使用协作式调度,这意味着它们在适当的时机主动让出控制权,从而允许其他协程执行。这种方式可以有效避免线程切换的开销。
- 事件循环: 在许多协程实现中(如 Python 的
asyncio),协程是在事件循环中运行的。事件循环负责调度和管理协程的执行。 - I/O 密集型任务: 协程特别适合处理 I/O 密集型任务(如网络请求和文件操作),因为在等待 I/O 操作完成时,协程可以挂起自己,让其他协程继续执行。
定时器注册
def register_timer(self, callback, waketime=NEVER):
timer_handler = ReactorTimer(callback, waketime)
timers = list(self._timers)
timers.append(timer_handler)
self._timers = timers
self._next_timer = min(self._next_timer, waketime)
return timer_handler
- 将一个回调函数注册到定时器队列中
定时器检查
def _check_timers(self, eventtime, busy):
if eventtime < self._next_timer:
if busy:
return 0.
if self._check_gc:
gi = gc.get_count()
if gi[0] >= 700:
# Reactor looks idle and gc is due - run it
gc_level = 0
if gi[1] >= 10:
gc_level = 1
if gi[2] >= 10:
gc_level = 2
self._last_gc_times[gc_level] = eventtime
gc.collect(gc_level)
return 0.
return min(1., max(.001, self._next_timer - eventtime))
self._next_timer = self.NEVER
g_dispatch = self._g_dispatch
for t in self._timers:
waketime = t.waketime
if eventtime >= waketime:
t.waketime = self.NEVER
t.waketime = waketime = t.callback(eventtime)
if g_dispatch is not self._g_dispatch:
self._next_timer = min(self._next_timer, waketime)
self._end_greenlet(g_dispatch)
return 0.
self._next_timer = min(self._next_timer, waketime)
return 0.
- 该函数主要是通过检查定时器的到期时间,决定是否执行定时器的回调函数,以及更新下一次检查定时器的时间。
- 如果未到定时器执行时间,判断状态是否忙碌,忙碌直接返回;否则进行垃圾回收操作
- 遍历定时器列表,回调定时器函数进行处理
- 在触发回调函数后,检查是否发生了协程切换。如果
g_dispatch和当前的_g_dispatch不一致,意味着其他协程已经接管控制,结束当前协程并返回。 - 循环结束后,更新下次要检查的定时器时间
self._next_timer,确保系统按时检查到期的定时器。
定时器更新
def update_timer(self, timer_handler, waketime):
timer_handler.waketime = waketime
self._next_timer = min(self._next_timer, waketime)
- 主要是更新定时器的执行时间,是否立即执行。
klippy — reactor模块的更多相关文章
- reactor官方文档译文(1)Reactor简介
原文地址:http://projectreactor.io/docs/reference/ Reactor简介 Reactor是一个基础库,用在构建实时数据流应用.要求有容错和低延迟至毫秒.纳秒.皮秒 ...
- twisted学习之reactor
reactor是twisted框架里面一个很重要的抽象,它为我们实现了循环,所以我们不用再去实现循环了. reactor有如下特点: 1.reactor循环会一致运行下去,可以使用Ctrl+C或者相关 ...
- twisted 源码分析一:reactor 单例
一个twisted进程只会有一个reactor反应器,下面我们来看看twisted是怎样实现这个单例反应器的, 路径:twisted\internet\reactor.py 主要代码如下: impor ...
- python基础===socket模块的讲解(转)
一.网络知识的一些介绍 socket 是网络连接端点.例如当你的Web浏览器请求www.jb51.net上的主页时,你的Web浏览器创建一个socket并命令它去连接 www.jb51.net的Web ...
- 学习响应式编程 Reactor (2) - 初识 reactor
Reactor Reactor 是用于 Java 的异步非阻塞响应式编程框架,同时具备背压控制的能力.它与 Java 8 函数式 Api 直接集成,比如 分为CompletableFuture.Str ...
- python 网络编程
一.网络知识的一些介绍 socket是网络连接端点.例如当你的Web浏览器请求www.pythontik.com上的主页时,你的Web浏览器创建一个socket并命令它去连接www.pythontik ...
- 使用Twisted进行socket编程
你的协议处理类通常是twisted.internet.protocol.Protocol的子类.许多协议处理继承于该类或者比该类更加方便的该类的子类.一个protocol类的实例可能反复连接,也可能在 ...
- Twisted框架
Twisted是一个事件驱动型的网络模型.时间驱动模型编程是一种范式,这里程序的执行流由外部决定.特点是:包含一个事件循环,当外部事件发生时,使用回调机制来触发相应的处理. 线程模式: 1.单线程同步 ...
- python2.0_s12_day10_Twsited异步网络框架
Twsited异步网络框架 Twisted是一个事件驱动的网络框架,其中包含了诸多功能,例如:网络协议.线程.数据库管理.网络操作.电子邮件等. Package application Configu ...
- socket网络编程【python】
转自:http://www.jb51.net/article/19751.htm socket 是网络连接端点. 一.网络知识的一些介绍 socket 是网络连接端点.例如当你的Web浏览器请求www ...
随机推荐
- 工作中的技术总结_JQuery_20210825
工作中的技术总结_JQuery_20210825 JQuery此前接触不多,所以先把此次接触的一些基本操作 1.DOM节点的取值或者赋值: 语法: $(selector).val(value) 参数 ...
- 3D数学基础:图形和游戏开发(第二版)--读书笔记(1)
简介: 本书是关于3D数学.三维空间的几何和代数的入门教材.它旨在告诉你如何使用数学描述三维中的物体及其位置.方向和轨迹.这不是一本关于计算机图形学.模拟,甚至计算几何的书,但是,如果读者打算研究这些 ...
- kubectl常用命令(二)
四.进入容器 # 进入pod容器,但是对权限要求也较多 kubectl exec -it podName sh # 通过bash获得 pod 中某个容器的TTY,相当于登录容器 kubectl exe ...
- 支持多语言、多商店的商城,.Net7 + EF7领域驱动设计架构
推荐一个跨平台.模块化.可扩展且超快速的开源一体化电子商务平台. 01项目简介 Smartstore 支持桌面和移动平台.多语言.多商店.多货币的商城,并支持SEO优化,支持无限数量的产品和类别.报表 ...
- Golang之数据库转换结构体工具table2struct
另外一个根据json生成对应结构体在线工具: https://mholt.github.io/json-to-go/ 安装: go get github.com/gohouse/converter 或 ...
- php-fpm相关操作
php-fpm常用操作 一. php5.3.3之后使用新号方式控制php-fpm进程 INT, TERM 立即终止 QUIT 平滑终止 USR1 重新打开日志文件 USR2 平滑重启所有worker进 ...
- nginx的子路径重写替换
在nginx中配置proxy_pass代理转发时,如果在proxy_pass后面的url加/,表示绝对根路径:如果没有/,表示相对路径,把匹配的路径部分也给代理走. 假设下面四种情况分别用 http ...
- 一款基于 .NET MVC 框架开发、功能全面的MES系统
前言 今天大姚给大家分享一款基于 .NET MVC 框架开发.功能全面的离散型零部件制造管理系统(MES):EasyMES. 项目介绍 EasyMES一款基于 .NET 6 MVC 框架开发.开源免费 ...
- R数据分析:冲击流图与热图的做法以及多图布局
今天看了一篇新冠肺炎相关后遗症的文章,主要探讨新冠住院病人一年后的后遗症情况,文章的统计分析很简单,不过结果展示中的两个图我觉的大家可以学一学,原文如下 Rivera-Izquierdo, M., L ...
- Microsoft Build 2022 专家对话
Microsoft Build 2022 专家对话 Build 2022 专家对话地址:https://mybuild.microsoft.com/en-US/sessions/81056450-6f ...