时间轮-理论篇

简介: 定时任务再开发过程中无处不在,定时发送消息,定时更新数据库表的状态,Linux系统定时执行脚本等等。这些操作都离不开定时任务,那么这些定时任务是怎么实现的是否又去想过。如果让开发者自己去实现一个定时任务又该怎么实现?时间轮

1. 引言

定时任务再开发过程中无处不在,定时发送消息,定时更新数据库表的状态,Linux系统定时执行脚本等等。这些操作都离不开定时任务,那么这些定时任务是怎么实现的是否又去想过。如果让开发者自己去实现一个定时任务又该怎么实现?

最简单的方案:定义一个链表,将要执行的任务添加到链表中。然后用线程去遍历链表,找出需要执行的任务进行执行。通过反复遍历任务链表就能实现定时任务的执行功能。

定时任务简单实现

但是上述方案有一个很重要的缺陷:如果我的任务有上百万个甚至更多的情况下,可能光遍历整个链表找出需要执行的任务就要花费一定量的时间。如果此时刚好有一个任务添加到链表的Tail,但是任务扫描的指针此时刚好在第一个Head任务节点。此时添加的任务执行时间就在添加后的20ms后,这个时候线程扫描到最后一个需要执行的任务的耗时可能超过了20ms,那么这种情况下就会出现任务的延迟执行。

Tips: 任务的延迟执行需要有一个合理的容忍范围。

在论文《Hashed and Hierarchical Timing Wheels》 提出了时间轮的概念来解决传统定时任务中的弊端

2. 时间轮简介

在生活中大家肯定见过指针手表(非电子手表)这个就可以看做时间轮,山地自行车的前后齿轮、水表的齿轮、以及减速齿轮都可以看做是时间轮。以手表的刻度为例子,机械手表上最长的指针每条以下表示1秒,也就是将一分钟分成了60个1秒。 时间轮的核心思想:将单位时间分成若干个时间间隔,每个时间间隔包含了时间单位除以若干时间间隔的时间量,时间轮转动到对应的时间间隔就执行当前时间间隔对应的可执行的任务。

下面用例子来说明:

1秒我们可以分成8个时间间隔,那么每个时间间隔就是125ms,如下图所示:

2.1 简单的时间轮

在论文《Hashed and Hierarchical Timing Wheels》 中每一个时间间隔叫做 bucket 。 bucket的作用用于存放当前时间间隔内存在的需要执行的任务。例如现在有四个任务A、B、C、D分别要在一秒的三个不同的时间段执行,A、B在两个不同的时间段执行,C、D在同一个时间段执行。那么在时间轮上的示意图如下:

简单时间轮示意图

当时间轮的指针从1Bucket的开始时间到结束时间段的过程中,会去遍历Bucket的链表中的任务,将需要执行的任务从链表中拿出来执行。已上图的例子每一秒时间轮的指针走一圈。

Tips: bucket中存放的任务是时间轮一个时间间隔中的任务,也就是说这些任务是一个时间段里面的任务。例如:100ms和80ms需要执行的任务都说存在bucket1。

进一步思考,如果你一分钟执行一次,那么时间轮的刻度就需要分成480个时间段,随着单位时间刻度的增加会让时间论的刻度越来越多。这样对于计算机来说就是消耗更多的内存。这种如何解决,在论文中提出另一个概念就是:分层时间轮

2.2 分层时间轮

在生活中分层时间轮也是比比皆是,例如在手表长最长的指针代表秒针,中间的代表分针,最短的代表时针。例如我有三个任务 A、B、C分别在以下时间执行:

  • A六十秒的时候执行一次
  • B十五分钟的时候执行一次
  • C六点位置的时候执行一次

如下图所示:

分层时间轮执行示意图

秒时间轮完成一圈触发分时间轮刻度往下一个,分时间轮完成一周触发时时间轮往下一个刻度。分层时间轮之间的刻度关系可以自己定义。不需要和时间刻度表上一样的。具体取决于业务的需要。例如:Linux的Corntab只支持分钟,而Java的Quartz可以支持到秒。

3.总结

时间轮是一种高效来利用线程资源来进行批量化调度的一种调度模型。提高利用率,但是时间轮调度器的时间精度可能不是很高,对于精度要求特别高的调度任务可能不太适合。因为时间轮算法的精度取决于,也就是时间间隔,时间间隔越小精度越高。时间轮的使用在各大框架与中间件中有使用,netty,kafka,jraft(这个是fork netty的)。

我是蚂蚁背大象,文章对你有帮助点赞关注我,文章有不正确的地方请您斧正留言评论~谢谢!
相关文章
|
8月前
|
消息中间件 存储 Apache
恭喜 Apache RocketMQ、Apache Seata 荣获 2024 开源创新榜单“年度开源项目”
近日,以“新纪天工、开物焕彩——致敬开源的力量”为活动主题的“重大科技成就发布会(首场)”在国家科技传播中心成功举办,并隆重揭晓了 2024 开源创新榜单,旨在致敬中国开源力量,传播推广开源科技成就,营造中国开源创新生态。2024 年开源创新榜单由中国科协科学技术传播中心、中国计算机学会、中国通信学会、中国科学院软件研究所共同主办,中国开发者社区承办,以王怀民院士为首组建评审委员会,进行研讨评审,面向中国开源行业领域,遴选具有创新性、贡献度和影响力的开源项目、社区、应用场景与开源事件。在评审出的 10 个年度开源项目中,Apache RocketMQ、Apache Seata 成功入选。
277 102
|
11月前
|
存储 缓存 负载均衡
使用一致性哈希让数据均匀分布
使用一致性哈希让数据均匀分布
194 2
|
9月前
|
机器学习/深度学习 数据采集 人工智能
《大模型训练成本高,如何在不牺牲性能的前提下破局》
在人工智能领域,大模型训练成本高昂,主要源于硬件设备、数据处理和算法优化的需求。降低训练成本的关键在于合理配置硬件资源、改进数据处理方法、优化算法和模型结构,以及采用分布式训练技术。通过这些措施,企业可以在不影响模型性能的前提下,显著减少计算资源、人力和时间的投入,实现更高效的模型训练。实践证明,综合运用这些方法能够有效降低成本,推动人工智能技术的可持续发展。
526 18
分布式事务的两阶段提交和三阶段提交分别有什么优缺点?
【9月更文挑战第9天】两阶段提交(2PC)和三阶段提交(3PC)是解决分布式系统事务一致性的机制。2PC实现简单,保证强一致性,但存在同步阻塞、单点故障和数据不一致风险。3PC通过引入超时机制减少阻塞时间,降低单点故障影响,但复杂性增加,仍可能数据不一致,并有额外性能开销。
458 9
|
消息中间件 Java 调度
消息队列 MQ使用问题之消费者自动掉线是什么导致的
消息队列(MQ)是一种用于异步通信和解耦的应用程序间消息传递的服务,广泛应用于分布式系统中。针对不同的MQ产品,如阿里云的RocketMQ、RabbitMQ等,它们在实现上述场景时可能会有不同的特性和优势,比如RocketMQ强调高吞吐量、低延迟和高可用性,适合大规模分布式系统;而RabbitMQ则以其灵活的路由规则和丰富的协议支持受到青睐。下面是一些常见的消息队列MQ产品的使用场景合集,这些场景涵盖了多种行业和业务需求。
|
11月前
|
存储 Rust 监控
使用 watchfiles 监控目录变更
使用 watchfiles 监控目录变更
236 2
|
12月前
|
数据安全/隐私保护 计算机视觉 Python
用python给照片添加水印的三种方式
这篇文章介绍了使用Python给照片添加水印的三种方式:通过PIL库直接添加文本水印、使用OpenCV库结合图像处理功能添加水印,以及使用filestools库进行更为简便的水印添加。
783 7
|
人工智能 监控 决策智能
震惊!多角色 Agent 携手合作,竟能如此高效搞定复杂任务,背后秘密大揭晓!
在复杂任务环境中,单个智能体常因能力与资源限制而难以应对。多智能体系统(multi-agent systems)通过将任务分解并分配给各具专长的智能体,实现了高效协同工作。例如,在物流配送中,不同智能体分别处理路线规划、货物装载与交通监控,确保任务准确高效完成。同样,在大型游戏开发项目里,各智能体专注剧情设计、美术创作等特定领域,显著提升项目质量和开发速度。通过共享信息、协商决策等方式,多智能体系统展现出强大灵活性与适应性,为物流、软件开发等领域带来新机遇。
470 2
|
12月前
|
存储 NoSQL 关系型数据库
数据存储架构的演进和实操(一)
数据存储架构的演进和实操(一)