阿里云-云小站(无限量代金券发放中)
【腾讯云】云服务器、云数据库、COS、CDN、短信等热卖云产品特惠抢购

sleep()到底睡多久,你知道吗?

389次阅读
没有评论

共计 3287 个字符,预计需要花费 9 分钟才能阅读完成。

sleep() 到底睡多久,你知道吗?

丁铎

 


2014 年毕业加入腾讯,对终端的性能测试有丰富的经验,《Android 移动性能实战》作者之一,现在从事后台的性能测试。

*** 本文共 2008 个字,阅读需要 5 分钟,本文经授权转自腾讯蓝鲸(微信号:Tencent_lanjing)

1. 背景

最近负责一个很简单的需求:在服务器上起一个后台进程,每隔 10 秒钟上报一下 CPU、内存等信息。就是这么简单的需求,发生了一个有趣的问题。

通过数据库查看上报的数据,发现 Windows 服务器在 5 月 24 号 14:59 到 15:12 之间,少上报了一个数据,少上报的数据会用 null 填充。但是看子机上的日志,这段时间均是按照预设的间隔成功上报,那问题出在哪儿呢?

开发一时也是一脸茫然,建议把测试时间调长,看是否能找到规律。好吧,那就把测试时间改到 19 个小时,这下还真的发现了一点规律。

sleep() 到底睡多久,你知道吗?

上图第一列是这段时间上报的数据点序列,即第 95 个点,第 419 个点,第二列是上报的信息,把所有的 null 过滤出来,看到相邻行的序号相差都在 320~330 之间,换算成时间,就是大概 55 分钟会少上报一个数据。

2. 原因排查

虽然找到了掉点的规律,但是从子机日志看都是上报成功的,是因为子机在这段时间就少采集了一个点吗?如果是这样的话,那么每次采样周期应该是超过 10s 的。

下面是信息采集上报的主循环代码,这里 m_iInterval 为 5,也就是在每个采样周期内,这个循环会执行两次,然后上报这两次中最大的值。

int nmISensor::execute(){    m_iInterval = INTERVAL;while(m_bFlag){updateData();Sleep(m_iInterval*1000);}m_acq=1;return SUCCEED;}

2.1 猜测 1:updateData() 有耗时,导致整个循环周期的时间大于预期

从上面的代码可以看出,每个上报周期,代码的执行逻辑如下示意图,我们第一反应是 updateData() 的执行肯定也会耗时,那么会导致整个采样周期大于 10s。一段时间后,就会少上报一个数据,幸福好像来的太突然。

sleep() 到底睡多久,你知道吗?

为了验证这个猜想,我们统计了一下 updataData() 的耗时,统计的结果看 updateData() 耗时都是 0,也就是 updateData() 基本上是不耗时的,事实和我们预想的并不一样。

2.2 猜想 2:Sleep() 有误差

排除了 updeData() 的原因,现在只能把目光聚焦在 Sleep 函数上,难道是 Windows 的 Sleep 函数实际休眠的时间和预期有差异?为了验证这个猜想,我们又在日志中打出了 Sleep 实际执行的耗时和预期之间的差异。

这次好像看到了希望,从输出的日志看,Sleep 最终休眠的时间会比预期多 15ms,这样以来,每个上报周期就会多 30ms,也就是在 55 分钟内可以上报 330 个点,现在只能上报 329 个点。

sleep() 到底睡多久,你知道吗?

那么问题来了,为什么在 Windows 上 Sleep() 会比预期的多 15ms 呢?

我们知道 Windows 操作系统基于时间片来进行任务调度的,Windows 内核的时钟频率为 64HZ,也就是每个时间片是 15.625 同时 Windows 也是非实时操作系统。对于非实时操作系统来说,低优先级的任务只有在子机的时间片结束或者主动挂起时,高优先级的任务才能被调度。下图直观地展示了两类操作系统的区别。

sleep() 到底睡多久,你知道吗?

sleep() 到底睡多久,你知道吗?

MSDN 上对 Sleep() 的说明:Sleep() 需要依赖内核的时间片,如果休眠时间在 1~2 时间片之间,那么最终等待的时间会是 1 个或者 2 个时间片,也就是 Sleep() 会有 0 -15.625(1 个时间片)的误差,那么到这里我们的问题也就弄清楚了。

sleep() 到底睡多久,你知道吗?

3. 解决方案

3.1 官方方案

微软官方针对 Sleep 耗时不精确的问题,也给出相应的解决方案:

  1. 调用 timeGetDevCaps 获取时钟定时器能支持的最小粒度

  2. 在定时开始之前调用 timeBeginPeriod,这样会把时钟定时器设置为最小的粒度

  3. 在定时结束之后调用 timeEndPeriod,恢复时钟定时器的粒度

同时,官方文档也指出 timeBeginPeriod 会对系统时钟、系统耗电和任务调度有影响,也就是 timeBeginPeriod 虽好,当不能滥用。

3.2 开发的方案

开发最后没有采用官方给的方案,毕竟频繁调用 timeBeginPeriod,带来的影响很难预估。而是采用了比较巧妙的方法:本次等待时长会减去上次多等的时间,即如果上次多等了 15ms,那么下次只用等 4895ms 就可以了,这样可以保证每次循环周期是 10s。

dwStart = GetTickCount();Sleep(dwInterval);dwDiff = GetTickCount() - dwStart - dwInterval;dwInterval = m_iInterval*1000;if (((long)dwDiff > 0) && (dwDiff < dwInterval)){dwInterval -= dwDiff;}

写到这里,问题已经解决,这时又有个疑惑涌上心头,Linux 服务器上有同样的上报功能,为什么 Linux 子机没有这个问题呢?难道 Linux 对应的开发是大婶,已了然这一切?

4. Linux 系统上 sleep() 是怎样的呢?

找到了 Linux 上对应的代码,原来这个开发哥并没有像 Windows 的开发哥那样自己去写一个定时的任务调度,而是用了一个开源的任务调度库 APScheduler,才免遭遇难。看来这里的奥秘都在这个开源库中,接着就去看看 APScheduler 是怎样做任务调度的。APScheduler 主循环的代码如下,红框圈出了一行关键的代码,这行代码的意思是:本次任务执行完成之后,在下次任务开始前需要等待 wait_sechonds 的时间。

sleep() 到底睡多久,你知道吗?

而 self._wakeup 是一个 Event 的对象,而 Event 正是 Python 系统库 threading 中定义的。而 Event 常用来做多线程的同步。

def __init__(self, gconfig={}, **options):    self._wakeup=Event()

官网对 Event.wait() 的解释:调用 wait() 之后,线程会一直阻塞,直到内部的 flag 设置为 true,或者超时。在没有别的线程设置 internal flag 时,wait() 就可以起到一个定时器的作用。

wait([timeout])Block until the internal flag is true. If the internal flag is true on entry, return immediately. Otherwise, block until another thread calls set() to set the flag to true, or until the optional timeout occurs.

那么问题又来了,Event.wait() 如果用作定时器,误差是多少呢?写个 demp 验证一下。

从测试数据看,Event.wait() 取 100 次的平均偏差为 0.1ms,而 time.sleep() 的平均偏差为 7.65ms,看起来 Event.wait() 精度更高。

sleep() 到底睡多久,你知道吗?

这里再回到我们第一个猜想,其实我们的猜想是合情合理的,如果 updateData() 的耗时较长,整个循环周期必定会超过预定的值,所以这里的实现并不严谨,而 APScheduler 则是通过起一个新的线程去执行任务,并不会阻塞循环周期,可以看到 APScheduler 在这里处理的还是很合理的。

sleep() 到底睡多久,你知道吗?

5. 结论

啰嗦了这么多,总结一下上面的内容:

  1. sleep() 在 Windows 和 Linux 系统上和预设值都会存在一个偏差,偏差最大为 1 个时间片的时间;

  2. Event.wait() 用来做定时器精度会更高,可以达到 0.1ms;

  3. APScheduler 看起来是个不错的任务调度库。


“Linuxy 云计算 25 期开班倒计时 5 天”

sleep() 到底睡多久,你知道吗?

正文完
星哥玩云-微信公众号
post-qrcode
 0
星锅
版权声明:本站原创文章,由 星锅 于2022-12-03发表,共计3287字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
【腾讯云】推广者专属福利,新客户无门槛领取总价值高达2860元代金券,每种代金券限量500张,先到先得。
阿里云-最新活动爆款每日限量供应
评论(没有评论)
验证码
【腾讯云】云服务器、云数据库、COS、CDN、短信等云产品特惠热卖中

星哥玩云

星哥玩云
星哥玩云
分享互联网知识
用户数
4
文章数
19348
评论数
4
阅读量
7801360
文章搜索
热门文章
开发者必备神器:阿里云 Qoder CLI 全面解析与上手指南

开发者必备神器:阿里云 Qoder CLI 全面解析与上手指南

开发者必备神器:阿里云 Qoder CLI 全面解析与上手指南 大家好,我是星哥。之前介绍了腾讯云的 Code...
星哥带你玩飞牛NAS-6:抖音视频同步工具,视频下载自动下载保存

星哥带你玩飞牛NAS-6:抖音视频同步工具,视频下载自动下载保存

星哥带你玩飞牛 NAS-6:抖音视频同步工具,视频下载自动下载保存 前言 各位玩 NAS 的朋友好,我是星哥!...
云服务器部署服务器面板1Panel:小白轻松构建Web服务与面板加固指南

云服务器部署服务器面板1Panel:小白轻松构建Web服务与面板加固指南

云服务器部署服务器面板 1Panel:小白轻松构建 Web 服务与面板加固指南 哈喽,我是星哥,经常有人问我不...
我把用了20年的360安全卫士卸载了

我把用了20年的360安全卫士卸载了

我把用了 20 年的 360 安全卫士卸载了 是的,正如标题你看到的。 原因 偷摸安装自家的软件 莫名其妙安装...
星哥带你玩飞牛NAS-3:安装飞牛NAS后的很有必要的操作

星哥带你玩飞牛NAS-3:安装飞牛NAS后的很有必要的操作

星哥带你玩飞牛 NAS-3:安装飞牛 NAS 后的很有必要的操作 前言 如果你已经有了飞牛 NAS 系统,之前...
阿里云CDN
阿里云CDN-提高用户访问的响应速度和成功率
随机文章
使用1Panel面板搭建属于你的AI项目环境

使用1Panel面板搭建属于你的AI项目环境

使用 1Panel 面板搭建属于你的 AI 项目环境 在 AI 项目越来越火的今天,很多朋友都想自己动手搭建一...
星哥带你玩飞牛NAS-5:飞牛NAS中的Docker功能介绍

星哥带你玩飞牛NAS-5:飞牛NAS中的Docker功能介绍

星哥带你玩飞牛 NAS-5:飞牛 NAS 中的 Docker 功能介绍 大家好,我是星哥,今天给大家带来如何在...
星哥带你玩飞牛NAS-4:飞牛NAS安装istore旁路由,家庭网络升级的最佳实践

星哥带你玩飞牛NAS-4:飞牛NAS安装istore旁路由,家庭网络升级的最佳实践

星哥带你玩飞牛 NAS-4:飞牛 NAS 安装 istore 旁路由,家庭网络升级的最佳实践 开始 大家好我是...
亚马逊云崩完,微软云崩!当全球第二大云“摔了一跤”:Azure 宕机背后的配置风险与警示

亚马逊云崩完,微软云崩!当全球第二大云“摔了一跤”:Azure 宕机背后的配置风险与警示

亚马逊云崩完,微软云崩!当全球第二大云“摔了一跤”:Azure 宕机背后的配置风险与警示 首先来回顾一下 10...
12.2K Star 爆火!开源免费的 FileConverter:右键一键搞定音视频 / 图片 / 文档转换,告别多工具切换

12.2K Star 爆火!开源免费的 FileConverter:右键一键搞定音视频 / 图片 / 文档转换,告别多工具切换

12.2K Star 爆火!开源免费的 FileConverter:右键一键搞定音视频 / 图片 / 文档转换...

免费图片视频管理工具让灵感库告别混乱

一言一句话
-「
手气不错
浏览器自动化工具!开源 AI 浏览器助手让你效率翻倍

浏览器自动化工具!开源 AI 浏览器助手让你效率翻倍

浏览器自动化工具!开源 AI 浏览器助手让你效率翻倍 前言 在 AI 自动化快速发展的当下,浏览器早已不再只是...
颠覆 AI 开发效率!开源工具一站式管控 30+大模型ApiKey,秘钥付费+负载均衡全搞定

颠覆 AI 开发效率!开源工具一站式管控 30+大模型ApiKey,秘钥付费+负载均衡全搞定

  颠覆 AI 开发效率!开源工具一站式管控 30+ 大模型 ApiKey,秘钥付费 + 负载均衡全...
星哥带你玩飞牛NAS-5:飞牛NAS中的Docker功能介绍

星哥带你玩飞牛NAS-5:飞牛NAS中的Docker功能介绍

星哥带你玩飞牛 NAS-5:飞牛 NAS 中的 Docker 功能介绍 大家好,我是星哥,今天给大家带来如何在...
支付宝、淘宝、闲鱼又双叕崩了,Cloudflare也瘫了连监控都挂,根因藏在哪?

支付宝、淘宝、闲鱼又双叕崩了,Cloudflare也瘫了连监控都挂,根因藏在哪?

支付宝、淘宝、闲鱼又双叕崩了,Cloudflare 也瘫了连监控都挂,根因藏在哪? 最近两天的互联网堪称“故障...
星哥带你玩飞牛NAS-7:手把手教你免费内网穿透-Cloudflare tunnel

星哥带你玩飞牛NAS-7:手把手教你免费内网穿透-Cloudflare tunnel

星哥带你玩飞牛 NAS-7:手把手教你免费内网穿透 -Cloudflare tunnel 前言 大家好,我是星...