如何统计毫秒级的时间差

计算毫秒级的时间差算是一个常见的需求吧...

手头上是windows编程的项目,所以首先就想到的是GetTickCount(),但MSDN上这么说:

写个程序试一下吧:

 1 #include <stdio.h>
 2 #include <windows.h>
 3
 4 int main(void)
 5 {
 6     DWORD dwLastTime = GetTickCount();
 7     for (int i = 0; i != 10; ++i)
 8     {
 9         DWORD dwCurrentTime = GetTickCount();
10         printf("GetTickCount = %ldms TimeDiff = %ldms\n", dwCurrentTime, dwCurrentTime - dwLastTime);
11         dwLastTime = dwCurrentTime;
12         Sleep(500);
13     }
14     return 0;
15 }

可以看到,算了10次,每次偏差一般都有1ms,更有甚者,达到15ms,跟MSDN里说的实际精度一样。

所以,用GetTickCount()计算毫秒级的时间差是不靠谱的!

那下面,如何满足我们的需求呢?

需求1:计算毫秒级别的时间差。

需求2:返回值最好是unsigned long级别的,以便与现有代码保持兼容。

解决方案1:

clock_t clock(void);

这个函数返回的是从程序启动到当前时刻所经历的CPU时钟周期数。将这个函数封装一下即可:

1 #include <ctime>
2
3 ULONG GetTickCountClock()
4 {
5     return (ULONG)((LONGLONG)clock() * 1000 / CLOCKS_PER_SEC);
6 }

测试结果:

解决方案2:

SYSTEMTIME FILETIME 

通过SYSTEMTIME和FILETIME,我们可以得到距离1601年1月1日凌晨所经历的时间,单位是100纳秒。

这个时间肯定是足够精确了,但是得到的数值是一个LONGLONG,没关系,我们可以用这个时间来校准原生的GetTickCount()。

 1 ULONG GetTickCountCalibrate()
 2 {
 3     static ULONG s_ulFirstCallTick = 0;
 4     static LONGLONG s_ullFirstCallTickMS = 0;
 5
 6     SYSTEMTIME systemtime;
 7     FILETIME filetime;
 8     GetLocalTime(&systemtime);
 9     SystemTimeToFileTime(&systemtime, &filetime);
10     LARGE_INTEGER liCurrentTime;
11     liCurrentTime.HighPart = filetime.dwHighDateTime;
12     liCurrentTime.LowPart = filetime.dwLowDateTime;
13     LONGLONG llCurrentTimeMS = liCurrentTime.QuadPart / 10000;
14
15     if (s_ulFirstCallTick == 0)
16     {
17         s_ulFirstCallTick = GetTickCount();
18     }
19     if (s_ullFirstCallTickMS == 0)
20     {
21         s_ullFirstCallTickMS = llCurrentTimeMS;
22     }
23
24     return s_ulFirstCallTick + (ULONG)(llCurrentTimeMS - s_ullFirstCallTickMS);
25 }

测试结果:

精度比较

每隔50ms获取一次当前时刻,对比TimeDiff与50之间的差距,统计1000次:

 1 #include <math.h>
 2
 3 int main(void)
 4 {
 5     int nMaxDeviation = 0;
 6     int nMinDeviation = 99;
 7     int nSumDeviation = 0;
 8
 9     DWORD dwLastTime = GetTickCountCalibrate();
10     Sleep(50);
11
12     for (int i = 0; i != 1000; ++i)
13     {
14         DWORD dwCurrentTime = GetTickCountCalibrate();
15         int nDeviation= abs(dwCurrentTime - dwLastTime - 50);
16         nMaxDeviation = nDeviation > nMaxDeviation ? nDeviation : nMaxDeviation;
17         nMinDeviation = nDeviation < nMinDeviation ? nDeviation : nMinDeviation;
18         nSumDeviation += nDeviation;
19         dwLastTime = dwCurrentTime;
20         Sleep(50);
21     }
22     printf("nMaxDiff = %2dms, nMinDiff = %dms, nSumDiff = %4dms, AverDiff = %.3fms\n",
23            nMaxDeviation, nMinDeviation, nSumDeviation, nSumDeviation / 1000.0f);
24
25     return 0;
26 }

比较GetTickCount、GetTickCountClock、GetTickCountCalibrate的精度如下:

1 GetTickCount           nMaxDiff = 13ms, nMinDiff = 3ms, nSumDiff = 5079ms, AverDiff = 5.079ms
2 GetTickCountClock      nMaxDiff =  2ms, nMinDiff = 0ms, nSumDiff =    4ms, AverDiff = 0.004ms
3 GetTickCountCalibrate  nMaxDiff =  1ms, nMinDiff = 0ms, nSumDiff =    3ms, AverDiff = 0.003ms

可以看到,原生的GetTickCount误差过大,最大误差13ms,平均误差5ms,肯定无法满足毫秒级的计时需求。

GetTickCountClock与GetTickCountCalibrate在精度上相差无几,都可以满足毫秒级的计时需求。

区别在于,GetTickCountClock是从当前程序运行开始计时,GetTickCountCalibrate是从系统启动开始计时。

有关溢出

4个字节的ULONG最大值是4294967296ms,也就是49.7天,超过这个值就会溢出。

时间: 2025-01-18 10:55:07

如何统计毫秒级的时间差的相关文章

shell脚本示例:计算毫秒级、微秒级时间差

有时候需要计算命令的执行时间长度,可以使用time命令,虽然time命令可以精确到毫秒级,但time命令无法计算一堆命令的执行时间.可以也可以直接使用date命令计算命令执行前后的时间差,但直接使用date命令计算时间差只能精确到秒级.因此,要计算毫秒级或者微秒级的时间长度,需要对date命令的结果进行一番计算转换. 本文只给出了毫秒级时间差的计算方法,若要计算微秒级时间差,对脚本稍作修改即可. 脚本如下: #!/bin/bash # filename: msec_diff.sh functio

毫秒级百万数据分页存储过程[欢迎转载]

数据分页一直是一个经久不衰的话题,在园子里看到了N多高手,都比我厉害, 今天把我使用的分页代码继续分享;请高手手下留情,少拍砖啦...哈哈; 欢迎大家转载!!!! 首先参考园子里的高手方法生成一个百万数据表; 耗时 33 秒; 然后创建分页存储过程;这个是基于SQL 2005 的ROW_NUMBER的, SQL 2000 不适用; SQL 2008 我没有安装,所以也没有测试过!估计应该可以运行. 2种算法可以选择 1. 使用  BETWEEN   ;  2.  TOP  ; 代码中已经注释了.

1.3万亿条数据查询如何做到毫秒级响应?

关注微信公众号"程序员黄小斜",选择"置顶或者星标" 一起成为更好的自己! ![](https://img2018.cnblogs.com/blog/1813797/201912/1813797-20191230133159470-930879899.jpg) 作者:孙晓光 出处:http://itindex.net/ 知乎,在古典中文中意为"你知道吗?",它是中国的 Quora,一个问答网站,其中各种问题由用户社区创建,回答,编辑和组织. 作为

大数据08 流计算(高速 毫秒级)

静态数据:比如数据仓库中的数据, 类似三峡水库中的水. (数据挖掘, OLAP 分析工具) 流数据:  网络监控, 传感检测, 大量的, 流式的数据(不断的产生, 源源不断的到达). 比如 PM2.5 的检测, 这种需要实时的监控和处理(分析). 流数据的特性 推送的方式: 实时查询的结果 流计算应用场景 电子商务网站, 根据用户输入, 实时分析, 然后推荐给用户分析结果. 实时交通: 实时的分析交通的情况, 给出分析导航建议. Storm 毫秒级架构 (免费开源) Topology : 就是一

c/c++中sleep()函数毫秒级的实现

近期看到好多人在问.c/c++中的sleep函数是秒级的,能不能实现毫秒级的呢?当然非常easy.我的写法例如以下 #include <stdio.h> #include <sys/select.h> static void sleep_ms(unsigned int secs) { struct timeval tval; tval.tv_sec=secs/1000; tval.tv_usec=(secs*1000)%1000000; select(0,NULL,NULL,NUL

在Windows及Linux下获取毫秒级运行时间的方法

在Windows下获取毫秒级运行时间的方法 头文件:<Windows.h> 函数原型: /*获取时钟频率,保存在结构LARGE_INTEGER中***/ WINBASEAPI BOOL WINAPI QueryPerformanceFrequency( _Out_ LARGE_INTEGER * lpFrequency ); /*获取从某个时间点开始的时钟周期数,保存在结构LARGE_INTEGER中**/ WINBASEAPI BOOL WINAPI QueryPerformanceFreq

C++计时器:毫秒级和微秒级

1.毫秒级 使用GetTickCount()获取系统启动所经过的毫秒数 #include<iostream> using namespace std; int main(){ DWORD start= ::GetTickCount(); //获取毫秒级数目 Sleep(1000); cout << ::GetTickCount() - start<< endl; system("pause"); } 2. 使用clock() #include <

WPF毫秒级桌面时钟的实现-C#中Hook(钩子)的应用

最近由于项目中需要精确记录某些操作的发生时间,但又没有办法打日志,因此写了个小工具,用来记录当前的毫秒级本机时间. (程序内部实现了全局钩子,监听所有的键盘事件,即KeyDown,KeyUp事件.) 工具功能如下: 1.通过任意键盘按键来记录当前时间 2.可以在列表处单击记录当前时间 C#中对于Hook API的包装如下: using System; using System.Collections.Generic; using System.Linq; using System.Reflect

Linux Shell获得毫秒级的时间戳

在linux Shell中并没有毫秒级的时间单位,只有秒和纳秒其实这样就足够了,因为纳秒的单位范围是(000000000..999999999),所以从纳秒也是可以的到毫秒的. current=`date "+%Y-%m-%d %H:%M:%S"`     #获取当前时间,例:2015-03-11 12:33:41        timeStamp=`date -d "$current" +%s`      #将current转换为时间戳,精确到秒 currentT