原标题:sleep()到底睡多久,你知道吗?

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

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

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

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

2. 原因排查

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

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

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

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

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

2.2 猜想2:Sleep()有误差

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

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

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

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

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

3. 解决方案3.1 官方方案

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

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

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

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

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

3.2 开发的方案

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

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

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

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

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

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

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

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

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

5. 结论

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

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

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

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

觉得本文有帮助?请分享给更多人

关注「猿助猿」成就顶级开发

技术交流QQ群:517877452返回搜狐,查看更多

责任编辑:

睡眠多少分钟一个循环_sleep()到底睡多久,你知道吗?相关推荐

  1. 睡眠多少分钟一个循环_关于科学睡眠丨90分钟一个睡眠周期,每晚循环3到5次...

    原创:柚子健康网微信号 快速动眼期持续一段时间后,人体又会进入非快速动眼期,如此交替,每个完整的睡眠周期大约持续90分钟,每夜睡眠一般需经过3-5个循环. 人的一生超过1/3的时间是在睡眠中度过的,科 ...

  2. 睡眠多少分钟一个循环_你知道睡眠周期吗?

    睡眠周期,是指睡眠存在一个生物节律,人们正常的睡眠结构周期分两个阶段:非快速眼动睡眠期(NREM)和快速眼动睡眠期(REM).NREM与REM交替出现,交替一次称为一个睡眠周期,两种循环往复,每夜通常 ...

  3. 睡眠多少分钟一个循环_什么是正常的睡眠?

    原标题:什么是正常的睡眠? 说起睡眠,很多人都以为一觉睡到天亮才是正常的,否则就是有问题.在门诊我们常遇到许多人向医生诉说后半夜易醒,醒了以后在睡觉就做梦:还有的人觉得整晚都在做梦,根本就没睡觉.那么 ...

  4. 睡眠多少分钟一个循环_人体血液循环一圈需要多长时间?

    1.人体血液循环一圈需要多长时间? 1.在胸外按压下,血液做一次周身循环的时间在3分钟左右:从外周静脉到右心房的血液循环时间为0.5~1分钟,血液做一次小循环的时间(右房到股动脉的间隔时间)为1分钟左 ...

  5. 睡眠多少分钟一个循环_睡眠分为几个阶段每个阶段大概多少时间?

    展开全部 阶段1:入睡期 第一阶段是睡眠的开始,脑电图的成32313133353236313431303231363533e58685e5aeb931333433636234分混合,频率和幅度都很低. ...

  6. 睡眠多少分钟一个循环_快速眼动周期-睡眠循环

    与所有的动物一样,人必须保证最基本的生理需求,也就是所谓的吃喝拉撒睡,人的一生有将近三分之一的时间花在睡眠上,可见睡眠对我们多么重要.正因如此,有人说:睡眠是利用一天三分之一的时间修补心灵的活动. 人 ...

  7. java 如何循环执行一个对象_一个Java对象到底有多大?

    编写Java代码的时候,大多数情况下,我们很少关注一个Java对象究竟有多大(占据多少内存),更多的是关注业务与逻辑.但是殊不知,在我们不经意间,大量的内存被无形地浪费了. 一个Java对象到底有多大 ...

  8. mysql当前时间减1小时_最佳睡眠时间:晚上睡眠不超8小时,午睡不超1小时

    最近,2020年的欧洲心血管学会 年会(ESC 2020)公布的两则研究摘要, 都是和睡觉有关的. 根据这两则研究, 可以得出最佳睡眠时间: 晚上睡眠不超8小时, 午睡不超1小时! 晚上睡超过8小时, ...

  9. 精讲深度学习RNN三大核心点,三分钟掌握循环神经网络

    本文将剖析循环神经网络(RNN)的工作原理,精讲循环神经网络的特点和实现方式.野蛮智能,小白也能看懂的人工智能. 循环神经网络从何而来? 我在我的这篇文章介绍了卷积神经网络(CNN)卷积神经网络(CN ...

最新文章

  1. Vue之v-on绑定监听事件
  2. SpringBoot高级-任务-定时任务
  3. Docker教程介绍
  4. android个推快速集成,个推用户画像产品(个像)Android集成实践
  5. 复杂业务下向Mysql导入30万条数据代码优化的踩坑记录
  6. Android AES加密算法及其实现
  7. Nginx valid_referer 防盗链
  8. pyspark调用spark以及执行带in语句参数的hql示例
  9. .NetCore下使用NPOI绘制统计图表
  10. 2023年云计算发展趋势会减缓吗?还能学习就业吗?
  11. 音频频谱显示-基于fmod设计音乐播放器并动态显示频谱图(二)
  12. C++ 在图片上打印文字并保存图片
  13. 国学入门书要目及其读法----梁启超
  14. 自己动手,编写神经网络程序,解决Mnist问题,并网络化部署-6CBIR模拟问题
  15. python接口自动化-发邮件带附件
  16. 报录比超过13:1的计算机专硕?211暨南大学公布报考人数!
  17. CVPR2020目标检测方向论文
  18. Google新书:《构建安全可靠的系统》
  19. spark环境安装及配置详细(附带相关错误及解决办法)
  20. 2021年P气瓶充装最新解析及P气瓶充装找解析

热门文章

  1. linux系统打开m3u8文件,linux:m3u8:如何从.m3u8中列出的段手动下载...
  2. Vue+Vux引入国际化
  3. python清单全套教程_编程最经典的一份python学习清单,零基础都可以学会的教程...
  4. 修饰符static、final、abstract与接口
  5. python——老鼠打洞问题
  6. html多个ul时怎么选择某个li,选中多个ul中的第一个li方法
  7. 熊猫烧香被恶搞,网友爆笑诗词句大集合[zz]
  8. 解决MoBaXterm网络连接超时问题Network error: Connection timed out
  9. make:commands commence before first target
  10. python监控文件夹_python2.6监控文件夹