5

Rust定时组件async-rs / futures-timer实现原理

 3 years ago
source link: https://segmentfault.com/a/1190000040396947
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

Rust定时组件async-rs / futures-timer实现原理

发布于 今天 03:42

项目中需要使用定时器,看了Rust官方提供的 futures-timer的源码 ,将实现原理这里记录下来。

以async-rs / futures-timer v3.0.0 源码为基础。

很多同学是java开发,因此与java的Timer对比,方便了解(待补充)。

另外本文不包含任何源码,这样不需要懂得Rust语言也能理解其中的设计原理。想看源码的同学,相信阅读本文以后再去看源码应该一目了然。

数据结构包含Delay、Heap、ArcList、Timer。
其中,Delay是用户定义的一个延迟任务,但仅包含延迟时间,没有设置任务来回调。Heap是一个最小堆,每个节点就是Delay,根据Delay的时间作为优先级,每次获取时间最近的Delay。ArcList是一个队列,其中的对象也是Delay。 Timer是总体的定时器,封装了Heap和ArcList。

控制组件包括waker(待补充)

插入任务:

用户创建Delay以后,写入ArcList后,由timer将Delay迁移到Heap中,最终Delay从Heap堆顶取出,完成整个生命周期。另外,ArcList支持并发写入,Heap不支持并发,这里ArcList起到一个消息队列的作用。

注册回调:

Delay任务插入Timer,也就是插入ArcList以后,同时也将Delay注册到监听器waker中,Waker是Timer中的一个监听器。当Delay任务在Heap中超时时,也就是从堆顶取出时,Waker触发Delay任务。这里的触发其实是一个future返回结果,Delay实现了future接口,当Delay注册到Timer以后,用户等待Delay的future完成,等Delay被触发时,future返回结果,以此达到定时效果。

Timer中有一个监听线程处理Heap堆里的Delay的超时,流程是取出堆顶的Delay以后,计算下一个Delay的时间,然后sleep。另外,当有新Delay插入时,也会唤醒这个线程,重新判断是否有Delay已经超时,然后再次sleep。

其他功能实现原理

时间重置
当修改之前已经存在的Delay的执行时间时,之前写入的Delay应该无效。采用的方法是,在Delay中增加两个计数字段,一个是现在重置过几次t,一个是任务写入Heap时t的值。当重置Delay时,将新生成一个Delay,两个计数字段都是t+1,插入ArcList,并且会修改Heap中原来的Delay,第一个计数字段变成t+1,而第二个字段还是t。当原来的Delay超时时,两个字段不一致,自动忽略。

官方提供async-rs / futures-timer组件。需要注意的是,async-rs / futures-timer在版本0.0.6以后将Interval功能删除了,Interval功能指的是固定周期定时任务功能,只保留了Delay功能,Delay功能指的是执行一次的任务。虽然Interval功能是对Delay做了一层封装Delay功能,但是用户手动实现还是有一定复杂度。

tokio也提供tokio::time组件,支持Delay功能、Interval功能、以及TimeOut功能,TimeOut功能指的是如果一个Future在指定时间内没有返回结果就超时。需要注意的是tokio::time只在["time"]feature上支持。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK