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

以async-rs / futures-timer v3.0.0 源码为根底。

很多同学是java开发,因而与java的Timer比照,不便理解(待补充)。

另外本文不蕴含任何源码,这样不须要懂得Rust语言也能了解其中的设计原理。想看源码的同学,置信浏览本文当前再去看源码应该高深莫测。

组成构造

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上反对。

参考

  • https://github.com/async-rs/f...
  • https://zhuanlan.zhihu.com/p/...
  • https://wiki.jikexueyuan.com/...
  • https://docs.rs/tokio/1.6.1/t...