───────────────────────────────────────────────────────────────
┌————————————┐
│▉▉♥♥♥♥♥♥♥♥ 99% │ ♥❤ 鱼沈雁杳天涯路,始信人间别离苦。
└————————————┘
对你的感情正在充电中,请稍侯…

────────────────────────────────────────────────────────────────

定时器方案红黑树,时间轮,最小堆

  • 一、如何组织定时任务?
    • 定时器收网络IO处理造成误差特别大,该怎么处理?
    • 用何种数据机构存储定时器?
      • 红黑树如何解决相同时间的key值的?
      • 最小堆
      • 时间轮
        • 一个帮助理解单层级时间轮的例子
        • 如何解决空推进的问题?
        • 为什么多线程使用时间轮
    • 设计哪些接口,如何设计?
    • 满足哪些条件才能作为定时器的数据结构?
  • 二、定时的方法有哪些?
    • 究竟什么是定时?
  • 三、总结

一、如何组织定时任务?

首先,定时器组件通常和网络组件一起工作。举个最简单的例子来说:

int event=epoll_wait(epfd,ev,nev,timeout);

timeout作为参数值,<0为一直阻塞,=0相当于非阻塞检测双端队列就绪情况0代表立刻返回,>0数值表示最长阻塞的时间。在时间上需要应对的问题填入epoll_wait函数,就可以兼顾网络事件的处理和定时任务的处理。

定时器收网络IO处理造成误差特别大,该怎么处理?

  • nginx,redis中通过定时信号去处理+epoll_wait解决,nginx_timer_revolusion()函数定时发送时间信号会打断epoll_wait()的处理,让它尽快的处理定时事件,从而解决了误差较大的问题。很明显,如果网络IO处理事件时,会造成一定的误差。定时任务事件处理=epoll_wait处理时间+网络事件处理时间。
//第一种:通过发送定时信号去打断epoll_wait函数
while(!quit)
{int now=get_now_time();//单位:msint timeout=get_nearest_time()-now;if(timeout<0)timeout=0;int nevent=epoll_wait(epfd,ev,nev,timeout);for(int i=0;i<nevent;i++){//网络事件处理}update_timer();、//时间事件处理
}
  • 单独开启一个线程,去处理定时任务。
//第二种:再其他线程添加定时任务
void* thread_timer(void * thread_param)
{init_timer();while(!quit){update_timer();sleep(t);}clear_timer();return nullptr;
}

用何种数据机构存储定时器?

考虑这个问题要清楚,越近要触发的事件优先级越高
定时器存在的意义是处理延时任务,具体来说比如:定期检测客户连接状态,心跳检测,技能冷却CD,倒计时,定时广播,界面实时刷新等等。

数据结构 应用 备注
红黑树 nginx 平衡二叉搜索树保证有序,利用时间作为键值,根据触发的时间来排序。
最小堆 libevent,go,libev 工作中大部分是最小堆。go和libev是最小四叉堆,一般是最小二叉堆。当有大量定时任务时,最小四叉堆比最小二叉堆有5%的性能提升。
多层级时间轮 netty,kafka,skynet,crontab netty是由JAVA开发。
跳表

红黑树如何解决相同时间的key值的?

大家知道,stl::map和stl::set是内部都是采用红黑树实现的,并没有要求key值一定要不同、

int find_nares_expire_timer(){ngx_rbtree_node_t *node;if(timer.root==&sentinel){return -1;}node=ngx_rbtree_min(timer.root,timer.sentinel);int diff=(int)node->key-(int)current_time();return diff>0 ? diff :0;
}

最小堆

最小堆是堆排序中一个子的流程,最小堆是一个完全二叉树(其他叶子节点都是满的,而最深的节点叶子都是靠在最左侧),用数组组织其中的元素。与用链表表示堆相比,数组表示堆不仅节省空间,而且更容易实现堆的插入、删除等操作。

  • 某个节点:x
  • 左子树索引:2x+1
  • 右子树索引:2x+2
  • 父节点索引:floor((x-1)/2)
    需要注意的是:最小堆只关注父子的大小,不关注兄弟的大小。
    增加节点只有上升操作,删除节点有上升和下降,个人理解不管是删除还是增加,都是要先对树进行操作,而后维护树的正常秩序。
    红黑树和最小堆的增删都是O(logn),在查找最小的就节点方面红黑树是O(logh),最小堆是O(log1),很明显最小堆比红黑树更加我稳定一些。

时间轮

crontab是linux的定时服务,它就是用时间轮实现的。与红黑树和最小堆不同的是,时间轮是多线程环境下使用的。
tcp的滑动窗口就是时间窗口的概念,这就是是单层级时间轮的实现。


  • 限流:动态的,5秒内有100次操作,换句话说一秒一秒的移动,限制在100次的操作。单层级时间轮就是实现的限流这个操作。更精确,但是
  • 熔断:静态的,5秒测一次,5秒测一次的感觉。
一个帮助理解单层级时间轮的例子

在客户端给服务器发送心跳的这个过程中,老师举例客户端可能五秒发一次服务器十秒检测一次,如果没有收到心跳就会踢除连接。检测是否有过期连接的方法有两种:一种是每一个连接启动一个定时器,另一种是将所有的连接存放在map<int,connect *>中,用一个定时器去检测上万个连接,因为有很多是新上来的连接,每秒去检测肯定是有很多次浪费的检测。
要设计单层级时间轮要从两个方面考虑:一个是检测间隔时间的大小,另一个是时间轮的精度。

公式:(5+10)/8=7

  • 5表示当前时间。
  • 10表示检测周期。
  • 8表示连接数。

计算机内部取余操作m%n=m-n*floor(m/n),x%16=x &(16-1)。
时间轮根本就不怕任务多,任务越多越好。

如何解决空推进的问题?
  • kafka利用的是最小堆+单层级时间轮
  • 多层级时间轮
为什么多线程使用时间轮

多线程要加锁,条件反射第一反应是锁的粒度。增加删除节点的时间复杂度都是O(log1),所以锁的粒度是最小的。上面也说到,红黑树和最小堆的时间复杂度都是O(logn),所以都使用时间轮。

设计哪些接口,如何设计?

笔者认为,分析定时器该如何设计,当有新设计需求时完全可以借用此模式,所以是有必要用心学的。

//初始化定时器
void init)timer();
//添加定时器
Node * add_timer(int expire,callback cb);
//删除定时器
bool del_timer(Node* node);
//找到最近发生的定时任务
Node* find_nearest_timer();
//清除定时器
void clear_timer();

满足哪些条件才能作为定时器的数据结构?

  • 能够快速找到这个节点,增加和删除。
  • 能够快速找到最小节点。

二、定时的方法有哪些?

究竟什么是定时?

定时是指在一段时间后欻某段代码的机制,我们可以利用这段代码有条不紊的处理所有到期的定时器。定时机制是定时器得以比处理的原动力。Linux有三种定时方法:

  • socket选项SO_RCVTIMEO和SO_SNDTIMEO。
  • SIGALARM信号。
  • I/O复用系统调用的超时参数。(上文提到的epoll_wait())。

socket选项的SO_RCVTIMEO和SO_SNDTIMEO是用来设置socket几首数据和发送数据超时时间的。send,sendmsg,rcv,recvmsg,accept和connect等系统调用都可以设置这个选项,根据这些系统调用的返回值以及errno来判断超时时间是否一道,然后去处理超时任务。
SIGALARM信号是当alarm()和settimer()函数设置实时闹钟时被触发,然后我们利用这个信号的信号处理函数来处理定时任务。定时周期T反应了定时的精度,如果某个定时任务的超时时间不是T的整数倍,那么它实际被执行的时间和恶预期的时间将略有偏差。
Linux下的三组I/O复用系统调用都带有超时参数,因此不仅能统一处理信号和I/事件,也能同意处理定时事件。值得注意的是:I/O复用系统调用可能在超时时间到期内就返回(I/O事件发生)。如果我们要利用它们来定时,就需要不断的更新定时参数以反映剩余的时间。
更多的细节内容还要细致的研读游双先生的《Linux高性能服务器编程》。

三、总结

通过零上学院Mark老师精彩的讲述定时器,让小生在定时器这个方面有了新的认识和突破,给鄙人领入了新的世界,开启了新的大门。
想想曾经,小可只沉溺于Qt中的QTimer类,就像一个烂醉如泥的懒汉,终日沉迷于花天酒地,只知开(颠)开(鸾)心(倒)心(凤)的酣畅,却不知阳春白雪正在向自己告别。虽然能够完成简单的任务,但是却从来没有发现其中藏着如此多的秘密。
现在的我,更像是一个满身泥泞,刚刚从大海中登陆抢滩的战士。
在Mark老师吹响嘹亮的冲锋号声中,尽管前进的道路上充满荆棘坎坷,但是为了胜利和尊严,不惜一切代价,奋勇争先。
生命不息,战斗不止

Linux服务器开发,定时器方案红黑树,时间轮,最小堆相关推荐

  1. 2022年3月28日记:Linux服务器开发,二叉树与红黑树

    ──────────────────────────────────── ┌------------┐ │▉▉♥♥♥♥♥♥♥♥ 99% │ ♥❤ 鱼沈雁杳天涯路,始信人间别离苦. └--------- ...

  2. 后端开发【一大波有用知识】定时器方案红黑树,时间轮,最小堆

    目录: 一.如何组织定时任务? 定时器收网络IO处理造成误差特别大,该怎么处理? 用何种数据机构存储定时器? 红黑树如何解决相同时间的key值的? 最小堆 时间轮 一个帮助理解单层级时间轮的例子 如何 ...

  3. C/C++Linux服务器开发高级架构师/Linux后台开发架构师丨高级进阶学习

    01 课程介绍 [录播]课程介绍(66分钟) 免费试学 [录播]磁盘存储链式的B树与B+树(131分钟) 免费试学 免费学习视频链接点击:C/C++Linux服务器开发高级架构师/Linux后台架构师 ...

  4. 【零声教育】C/C++Linux服务器开发/高级架构师 课程

    随着去年年底的疫情,很多线下的学习都变成了网课的形式,各种付费学习也萌生出来,很多决定要报名付费网课例如零声学院C/C++linux后台服务器高级架构师的程序员,报名之前总会问我这样一个问题,除了视频 ...

  5. 如何快速实现分布式定时器丨红黑树|跳表|堆|时间轮|缓存|锁|事务|架构|高性能|消息队列丨C/C++Linux服务器开发丨C++后端开发

    如何快速实现分布式定时器 视频讲解如下,点击观看: 如何快速实现分布式定时器丨红黑树|跳表|堆|时间轮|缓存|锁|事务|架构|高性能|消息队列丨C/C++Linux服务器开发丨C++后端开发丨中间件 ...

  6. 红黑树在linux内核中的应用场景(红黑树,进程管理CFS,内存管理)丨epoll丨c/c++linux服务器开发丨linux后台开发

    红黑树在linux内核中的应用场景(红黑树,进程管理CFS,内存管理) 视频讲解如下: 红黑树在linux内核中的应用场景(红黑树,进程管理CFS,内存管理)丨epoll丨c/c++linux服务器开 ...

  7. 详解5种红黑树的场景,从Linux内核谈到Nginx源码,听完醍醐灌顶丨Linux服务器开发丨Linux后端开发

    5种红黑树的场景,从Linux内核谈到Nginx源码,听完醍醐灌顶 1. 进程调度CFS的红黑树场景 2. 虚拟内存管理的红黑树场景 3. 共享内存slab的红黑树场景 视频讲解如下,点击观看: [干 ...

  8. 10年后端开发程序员详解数据库缓存方案到底有多少名堂。丨Linux服务器开发丨后端开发丨中间件丨web服务器丨数据库缓存

    数据库缓存方案到底有多少花样,一节课带你缕清 1. 读写分离方案 2. 若干个缓存解决方案 3. 缓存故障如何解决 视频讲解如下,点击观看: 10年后端开发程序员详解数据库缓存方案到底有多少名堂.丨L ...

  9. Linux服务器开发初步

      服务器开发需要考虑的内容很多,比如服务器的架构.稳定性.性能以及负载能力等等. 事实上,在开发服务器的过程中,需要综合考虑各种因素,比如就客户端连接时间较短却又比较频繁的服务器(例如HTTP服务器 ...

最新文章

  1. 解决输入法图标不见了,控制面板里面也无法设置
  2. PLSQL_数据泵Datapump导入导出数据IMPDP / EXPDP(概念)(Oracle数据导入导出工具)(转)...
  3. 【opencv系列06】OpenCV4.X滑动条操作
  4. c语言的程序框图怎么写,C语言课程设计————写下流程图! 谢谢
  5. apache.camel_Apache Camel K 1.0在这里–您为什么要关心
  6. 注释工具_苹果已购丨Notability丨功能强大而简单易用的笔记及PDF注释工具
  7. 如何处理分析Flink作业反压的问题?
  8. 今天遇到个超郁闷的问题
  9. 【图像融合】基于matlab GUI SIFT+小波变换图像拼接融合系统【含Matlab源码 815期】
  10. SAI+PS超萌Q版插画手绘视频教程
  11. matlab画EBSD的极图,EBSD技术原理及系统.PDF
  12. 无法启动程序因为计算机中丢失msvcr100,win7系统无法启动程序提示计算机中丢失msvcr100.dll的解决方法...
  13. 姜烧猪肉+日式厚蛋烧+蚝油青笋
  14. 根据音乐播放进度实时更新音乐播放器播放进度条
  15. 增加seo好感度,wordpress给文章增加og协议,即meta标签形式如 meta property=”og:
  16. Linux Framebuffer驱动剖析之一—软件需求
  17. 我也不知道说什么....
  18. 动手实现天气预报App(一)——数据、工具类和碎片布局准备
  19. 如何访问网络上其他计算机,电脑怎么连接别的网络
  20. 什么是数字化供应链系统?企业如何利用数字化供应链系统增加销售渠道?

热门文章

  1. 用人单位订立哪些规章制度必须与职工协商
  2. C++运算符重载之加号运算符重载
  3. 海贼王热血航线服务器维护4月,《航海王热血航线》4月29日停服更新公告
  4. linux系统mysql服务启动失败
  5. K8s部署Heapster踩坑记录
  6. VMware vSphere client 中英文语言界面设置
  7. echart 关系图graph配置文件
  8. React 虚拟DOM
  9. JS按钮点击事件实现弹窗(popup)
  10. Python Web开发(六):前后端分离的架构