开源框架中的“轮子”往往能带来让人惊艳的设计,在此,尝试总结轮子设计适合的场景。
经典的轮子设计
- dubbo定时任务时间轮
- Disruptor追踪序列轮
相似点
基于一个2的幂次方容量的数组,通过在其上循环往复来达成如下目标:
- 定位下标只常数时间
- 充分利用局部性原理
- 用空间降低时间维度的局部竞争
- 降低fullGC的成本
差异点
- 槽位任务数量
dubbo的时间轮槽位仅持有一个任务管理器,具体任务通过双向链表串联,从而一个槽位实际可关联n个任务。
Disruptor的追踪序列上承载的是具体的任务实体,每一个发布的任务都是赋值,而不是新建,故实际一个槽位仅关联一个任务。
- 驱动方式
dubbo的时间轮会按规则不断的tick+1累计,然后基于掩码计算出当前需要触发的槽位下标,进而触发该槽位关联的任务。
Disruptor的追踪序列则由生产者的发布事件&消费者的消费事件相互影响驱动。
- 存储
dubbo的槽位是存放的任务管理者,一旦创建不会变更,也没做什么缓存行填充之类的优化,因为时间轮线程,无并发竞争,任务都是堆积在队列中,且随时间轮不断的分发给具体的槽位。
Disruptor的槽位是具体的任务引用,因为使用场合会面临大量竞争的可能性,故使用了缓存行填充技术,规避不必要的竞争。
轮子适合的场合
需要o(1)操作具体元素
需要尽可能降低fullGC的影响
容量允许2的幂次方
需要大并发竞争
程序的局部性对性能有明显影响
参考:
https://www.cse.wustl.edu/~cdgill/courses/cs6874/TimingWheels.ppt