Linux高性能服务器——定时器

定时器

定时是指在一段时间之后触发某段代码的机制,我们可以在这段代码中依次处理所有到期的定时器。换言之,定时机制是定时器得以被处理的原动力。Linux 提供了三种定时方法:

  • socket 选项 SO_RCVTIMEOSO_SNDTIMEO
  • SIGALRM 信号;
  • I/O 复用系统调用的超时参数;

定时方法

1. socket 选项 SO_RCVTIMEOSO_SNDTIMEO

这两个选项仅对与数据接收和发送相关的 socket 专用系统调用有效,如:send、sendmsg、recv、recvmsg、accept 和 connect。

系统调用有效选项系统调用超时后的行为
sendSO_SENDTIMEO返回-1,设置 errno 为 EAGAIN 或 EWOULDBLOCK
sendmsgSO_SENDTIMEO返回-1,设置 errno 为 EAGAIN 或 EWOULDBLOCK
recvSO_RCVTIMEO返回-1,设置 errno 为 EAGAIN 或 EWOULDBLOCK
recvmsgSO_RCVTIMEO返回-1,设置 errno 为 EAGAIN 或 EWOULDBLOCK
acceptSO_RCVTIMEO返回-1,设置 errno 为 EAGAIN 或 EWOULDBLOCK
connectSO_SENDTIMEO返回-1,设置 errno 为 EINPROGRESS

在程序中,我们可以根据系统调用的返回值以及 errno 来判断超时时间是否已到,进而决定是否开始处理定时任务。

2. SIGALRM 信号

由 alarm 和 setitimer 函数设置的实时闹钟一旦超时,将触发 SIGALRM 信号。如果要处理多个定时任务,就需要不断地触发 SIGALRM 信号,并在其信号处理函数中执行到期的任务。一般而言,SIGALRM 信号按照固定的频率生成,由 alarm 和 setitimer 函数设置的定时周期 T 保持不变。如果某个定时任务的超时时间不是 T 的整数倍,那么实际被执行的时间会与预期有偏差。因此 T 反映了定时的精度。

基于升序链表的定时器

定时器通常包括两个成员:超时时间和任务回调函数。有的时候还包括回调函数的参数以及是否重启定时器等信息。

链表作为容器的话还需要指向上一个或下一个定时器的指针成员。

// P196 + P200
  • 添加定时器的时间复杂度是:O(n)
  • 删除定时器的时间复杂度是:O(1)
  • 执行定时任务的时间复杂度是:O(1)

3. I/O 复用系统调用的超时参数

Linux 下的三组 I/O 复用系统调用都带有超时参数,因此它们不仅可以统一处理信号和 I/O 事件,也能统一处理定时事件。但是由于 I/O 复用系统调用可能在超时时间到期之前就返回(有 I/O 事件发生),所以如果要利用它们来定时,就需要不断更新定时参数以反映剩余的时间。

#define TIMEOUT 5000int timeout = TIMEOUT;
time_t start = time(NULL);
time_t end = time(NULL);
while(1){start = time(NULL);int number = epoll_wait(epollfd, events, MAX_EVENT_NUMBER, timeout);if((number < 0) && (errno != EINTR)){// epoll failurebreak;}if(number == 0){// 如果返回0,则说明超时时间已到,此时可以处理超时任务,并重置定时时间timeout = TIMEOUT;continue;}end = time(NULL);// 更新定时参数timeout -= (end - start) * 1000;if(timeout <= 0){// 处理超时任务,并重置定时时间timeout = TIMEOUT;}
}

高性能定时器

1. 时间轮

基于排序链表的定时器存在一个问题:添加定时器的效率偏低,时间轮解决了这个问题。

指针指向轮子上的一个槽,它以恒定的速度顺时针转动,每转动一步就指向下一个槽,每次转动称为一个滴答(tick)。一个滴答的时间称为时间轮的槽间隔 si,转动一周的时间是 N × si。每个槽指向一条定时器链表,每条链表上的定时器具有相同的特征:**它们的定时时间相差 N × si 的整数倍。**时间轮正是利用这个关系将定时器散列到不同的链表中。

计算待插入的定时器应该被插入到哪个槽中:

假如现在指针指向槽 cs,要添加一个定时时间为 ti 的定时器,则该定时器将被插入槽 ts 对应的链表中:ts = (cs + (ti / si)) % N

对于时间轮而言:

  • 要提高定时精度,就要使 si 足够小;

  • 要提高执行效率,就要使 N 足够大;

  • 添加定时器的时间复杂度是:O(1)

  • 删除定时器的时间复杂度是:O(1)

  • 执行定时任务的时间复杂度是:O(n)

// P207

2. 时间堆

时间堆的特殊之处:不再使用固定的频率调用 tick,而是将所有定时器中超时时间最小的一个定时器的超时值作为心搏间隔。

一旦 tick 被调用,超时时间最小的定时器一定到期,就可以在 tick 函数中处理该定时器。然后,再次从剩余的定时器中找出超时时间最小的一个,并将这段最小时间设置为下一次心搏间隔。如此反复,就实现了较为精确的定时。

由于最小堆是一种完全二叉树,所以可以用数组来组织其中的元素。对于数组中的任意位置 i 上的元素,其左儿子节点在位置 2i+1 上,其右儿子节点在位置 2i+2 上,其父节点在位置 [(i - 1) / 2] (i > 0) 上。与用链表来表示堆相比,用数组表示堆不仅节省空间,而且更容易实现堆的插入、删除等操作。

// P212
  • 添加定时器的时间复杂度是:O(lgn)
  • 删除定时器的时间复杂度是:O(1)
  • 执行定时任务的时间复杂度是:O(1)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/77940.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

领域驱动设计:领域模型与代码模型的一致性

文章目录 领域对象的整理从领域模型到微服务的设计领域层的领域对象应用层的领域对象 领域对象与微服务代码对象的映射典型的领域模型非典型领域模型 DDD 强调先构建领域模型然后设计微服务&#xff0c;以保证领域模型和微服务的一体性&#xff0c;因此我们不能脱离领域模型来谈…

树控件、下拉框、文本框常用测试用例

01 控件的测试外观操作 1&#xff09;项目中的所有树是否风格一致 2&#xff09;树结构的默认状态是怎样的。比如默认树是否是展开&#xff0c;是展开几级&#xff1f; 是否有默认的焦点&#xff1f;默认值是什么&#xff1f;展开的节点图标和颜色&#xff1f; 3&#xff09…

Matlab之创建空数组的多种方法汇总

一、matlab空数组是什么&#xff1f; 在MATLAB中&#xff0c;空数组是指没有元素的数组对象。它可以用于占位或者作为容器&#xff0c;等待后续添加元素。 二、创建空数组的多种方法 1、使用空方括号 [] 创建空矩阵 A []; % 创建一个空双精度矩阵 B logical([]); % 创建一…

TypeScript类型系统层级

&#x1f3ac; 岸边的风&#xff1a;个人主页 &#x1f525; 个人专栏 :《 VUE 》 《 javaScript 》 ⛺️ 生活的理想&#xff0c;就是为了理想的生活 ! 目录 1. 顶层类型&#xff08;Top Type&#xff09; 1.1 any 类型 1.2 unknown 类型 2. 底层类型&#xff08;Bottom …

linux设备树节点添加新的复位属性之后设备驱动加载异常问题分析

linux设备树节点添加新的复位属性之后设备驱动加载异常问题分析 1 linux原始设备驱动信息1.1 设备树节点信息1.2 linux设备驱动1.3 makefile1.4 Kconfig1.5 对应的defconfig文件 2 修改之后的linux设备驱动2.1 修改之后的设备树节点信息2.2 原始test_fw.c出现的问题以及原因分析…

达观RPA实战-编码与解码

一、应用背景 项目中我们经常需要获取某个服务的JSON数据。如果响应返回的是JSON格式的数据,客户端通过JSON工具可正常解析。但如果碰到值里面有中文的,特别是返回的格式是类似“{"name": "\u5927\u7231\u4e2d\u56fd"}”处理起来会比较麻烦。本文将从编…

【PyCharm Community Edition】:分析map文件统计RAM及ROM的使用

遍历文件 前序文件遍历WalkFiles.py统计方法AnalyzerMap.py主函数main.py延伸阅读前序 当我们的编译器不方便统计代码的RAM及ROM的使用总数量时,我们就需要分析.map文件,手动统计其具体使用量。 文件遍历 当我们需要选择不同文件做相同的逻辑处理时,我们就会用到一种遍历…

【Git】Git 快照 Snapshot

Git 快照 Snapshot 在对 Git 基础的学习过程中&#xff0c;我们了解了 Git 仓库的基本结构&#xff1a; 工作目录暂存区版本库&#xff0c;即 .git 仓库 下面我们就通过一次修改、暂存以及提交的工作流程&#xff0c;来理解快照&#xff08;Snapshot&#xff09;的概念。 现…

【C语言】每日一题(半月斩)——day1

目录 &#x1f60a;前言 一.选择题 1.执行下面程序&#xff0c;正确的输出是&#xff08;c&#xff09; 2.以下不正确的定义语句是&#xff08; &#xff09; 3.test.c 文件中包括如下语句&#xff0c;文件中定义的四个变量中&#xff0c;是指针类型的变量为【多选】&a…

The specified module could not be found.

新电脑运行项目的时候出现了某个包找不到的问题 \\?\D:\guanwnag\cloudquery-website\node_modules\.pnpm\nxnx-win32-x64-msvc16.5.3\node_modules\nx\nx-win32-x64-msvc\nx.win32-x64-msvc.node 引入的路径就感觉有问题 去github上查找原因&#xff0c;发现是没安装 Micro…

Anaconda下Jupyter Notebook执行OpenCV中cv2.imshow()报错(错误码为1272)网上解法汇总记录和最终处理方式

零、我设备的相关信息 Python 3.8.8Anaconda3 2021.05查询匹配python3.8.*的OpenCV匹配版本为&#xff1a;4.1.* — 4.2.*&#xff0c;我最后安装4.2.0.32版本如下我记录了 “从发现问题&#xff0c;到不断试错&#xff0c;最后解决问题” 的完整过程&#xff0c;以备自己复盘…

【Java基础篇 | 面向对象】--- 聊聊什么是多态(上篇)

个人主页&#xff1a;兜里有颗棉花糖 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 兜里有颗棉花糖 原创 收录于专栏【JavaSE_primary】 本专栏旨在分享学习JavaSE的一点学习心得&#xff0c;欢迎大家在评论区讨论&#x1f48c; 目录 一、什么是多态二、多…

IIC总线上拉电阻计算

IIC总线上拉电阻计算 1. 概述2. 上拉电阻计算3. 总线传输速度与功率4. 实例计算 1. 概述 IIC&#xff08;Inter-Integrated Circuit&#xff09;其实是IICBus简称&#xff0c;所以中文应该叫集成电路总线&#xff0c;它是一种串行通信总线&#xff0c;使用多主从架构&#xff…

【PowerQuery】Excel的PowerQuery的复制

在Excel中构建符合要求的PowerQuery连接之后&#xff0c;所有的PowerQuery 连接已经顺利的保存在Excel 工作簿当中&#xff0c;但是如何去查看已经保存的PowerQuery连接呢&#xff1f;图6.3 显示了查看PowerQuery连接。 Excel界面->数据页签->查询与连接 如果你的Power…

Redis从入门到精通(四:持久化)

持久化简介 什么是持久化 利用永久性存储介质将数据进行保存&#xff0c;在特定的时间将保存的数据进行恢复的工作机制称为持久化 持久化用于防止数据的意外丢失&#xff0c;确保数据安全性 为什么持久化 redis是将数据存储在内存上的&#xff0c;一旦断电&#xff0c;或者因…

.NET Framework 2023 年 8 月安全和质量汇总更新

作者&#xff1a;Salini Agarwal 排版&#xff1a;Alan Wang 今天&#xff0c;我们发布了针对 .NET Framework 的2023 年 8 月安全和质量汇总更新。 安全 CVE-2023-36899 – .NET Framework 远程代码执行漏洞 此安全更新修复了 IIS 上的应用程序存在的一个漏洞&#xff0c;该…

c++类与对象(中)

文章目录 前言一、构造函数1、构造函数介绍2、构造函数特性 二、析构函数1、析构函数介绍2、析构函数特性 三、拷贝构造函数1、拷贝构造函数介绍2、拷贝构造函数特征3、拷贝构造函数的应用 -- 求n天后的日期 四、赋值运算符重载1、运算符重载2、一些运算符重载的实现3、赋值运算…

安徽省图书馆典藏《乡村振兴振兴战略下传统村落文化旅游设计》许少辉八一新著

安徽省图书馆典藏《乡村振兴振兴战略下传统村落文化旅游设计》许少辉八一新著

Java生成微信小程序二维码,5种实现方式,一个比一个简单

文章目录 前言先看官网一、JDK自带的URLConnection方式二、Apache的HttpClient方式三、okhttp3方式四、Unirest方式五、RestTemplate方式其它细节getAccessToken构建参数mapbyte[]数组 源码下载 前言 先介绍一下项目场景&#xff0c;主要是通过微信小程序二维码裂变分享&#…

MySQL之数据类型

目录 一、MySQL数据类型分类 二、数值类型 1、整数类型 2、bit类型 3、小数类型 三、字符串类型 1、char 2、varchar 3、char和varchar比较 四、日期和时间类型 五、enum和set 一、MySQL数据类型分类 MySQL 数据类型可以大致分为以下三类&#xff1a; 数值类型&#xff1a;用于…