计算程序运行时间的函数Sleep,clock,GetTickCount,QueryPerformanceCounter

本文详细介绍了Windows操作系统下多种常用时间函数及定时器的使用方法、原理、精度和应用场景,包括Sleep函数、MFC下的timer事件、C语言下的time函数等,并对比了它们之间的区别和优缺点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

转自:http://blog.youkuaiyun.com/augusdi/article/details/10960231

介绍

我们在衡量一个函数运行时间,或者判断一个算法的时间效率,或者在程序中我们需要一个定时器,定时执行一个特定的操作,比如在多媒体中,比如在游戏中等,都 会用到时间函数。还比如我们通过记录函数或者算法开始和截至的时间,然后利用两者之差得出函数或者算法的运行时间。编译器和操作系统为我们提供了很多时间 函数,这些时间函数的精度也是各不相同的,所以,如果我们想得到准确的结果,必须使用合适的时间函数。现在我就介绍windows下的几种常用时间函数。

1:Sleep函数

使用:Sleep(1000),在Windows和Linux下1000代表的含义并不相同,Windows下的表示1000毫秒,也就是1秒钟;Linux下表示1000秒,Linux下使用毫秒级别的函数可以使用usleep。

原理:Sleep函数是使调用Sleep函数的线程休眠,线程主动放弃时间片。当经过指定的时间间隔后,再启动线程,继续执行代码。Sleep函数并不能起到定时的作用,主要作用是延时。在一些多线程中可能会看到sleep(0);其主要目的是让出时间片。

精度:Sleep函数的精度非常低,当系统越忙它精度也就越低,有时候我们休眠1秒,可能3秒后才能继续执行。它的精度取决于线程自身优先级、其他线程的优先级,以及线程的数量等因素。

2:MFC下的timer事件

使用:1.调用函数SetTimer()设置定时间隔,如SetTimer(0,100,NULL)即为设置100毫秒的时间间隔;2.在应用程序中增加定时响应函数OnTimer(),并在该函数中添加响应的处理语句,用来完成时间到时的操作。

原理:同Sleep函数一样。不同的是timer是一个定时器,可以指定回调函数,默认为OnTimer()函数。

精度:timer事件的精度范围在毫米级别,系统越忙其精度也就越差。

3:C语言下的Time

使用:time_t t;time(&t);Time函数是获取当前时间。

原理:time函数主要用于获取当前时间,比如我们做一个电子时钟程序,就可以使用此函数,获取系统当前的时间。

精度:秒级别

4:COM对象中的COleDateTime,COleDateTimeSpan类

使用:

COleDateTime start_time = COleDateTime::GetCurrentTime();  
COleDateTimeSpan end_time = COleDateTime::GetCurrentTime()-start_time;  
While(end_time.GetTotalSeconds() < 2)  
{  
// 处理延时或定时期间能处理其他的消息  
DoSomething()  
end_time = COleDateTime::GetCurrentTime-start_time;  
}  

原理:以上代表延时2秒,而这两秒内我们可以循环调用DoSomething(),从而实现在延时的时候我们也能够处理其他的函数,或者消息。COleDateTime,COleDateTimeSpan是MFC中CTime,CTimeSpan在COM中的应用,所以,上面的方法对于CTime,CTimeSpan同样有效。

精度:秒级别

5:C语言下的时钟周期clock()

使用:

[cpp] view plaincopy
clock_t start = clock();  
Sleep(100);  
clock_t end = clock();  
double d = (double)(start - end) / CLOCKS_PER_SEC;  

原理:clock()是获取计算机启动后的时间间隔。

精度:ms级别,对于短时间内的定时或者延时可以达到ms级别,对于时间比较长的定时或者延迟精度还是不够。在windows下CLOCKS_PER_SEC为1000。

6:Windows下的GetTickCount()

使用:

[cpp] view plaincopy
DWORD start = GetTickCount();  
Sleep(100);  
DWORD end = GetTickCount();  

原理:GetTickCount()是获取系统启动后的时间间隔。通过进入函数开始定时,到退出函数结束定时,从而可以判断出函数的执行时间,这种时间也并非是函数或者算法的真实执行时间,因为在函数和算法线程不可能一直占用CPU,对于所有判断执行时间的函数都是一样,不过基本上已经很准确,可以通过查询进行定时。GetTickCount()和Clock()函数是向主板BIOS要real time clock时间,会有中断产生,以及延迟问题。

精度:WindowsNT 3.5以及以后版本精度是10ms,它的时间精度比clock函数的要高,GetTickCount()常用于多媒体中。

7:Windows下timeGetTime

使用:需要包含Mmsystem.h,Windows.h,加入静态库Winmm.lib.
即添加#pragma comment( lib,”winmm.lib” )或在(VS2012)”项目–属性–链接器–输入–附加依赖性”中,添加winmm.lib。
timeBeginPeriod(1);
DWORD start = timeGetTime();
Sleep(100);
DWORD end = timeGetTime();
timeEndPeriod(1);
原理:timeGetTime也时常用于多媒体定时器中,可以通过查询进行定时。通过查询进行定时,本身也会影响定时器的定时精度。

精度:毫秒,与GetTickCount()相当。但是和GetTickCount相比,timeGetTime可以通过timeBeginPeriod,timeEndPeriod设置定时器的最小解析精度, timeBeginPeriod,timeEndPeriod必须成对出现。

8:windows下的timeSetEvent

使用:还记的VC下的Timer吗?Timer是一个定时器,而以上我们提到几种时间函数或者类型,实现定时功能只能通过轮训来实现,也就是必须另外创建一个线程单独处理,这样会影响定时精度,好在windows提供了内置的定时器timeSetEvent,函数原型为

MMRESULT timeSetEvent( UINT uDelay, //以毫秒指定事件的周期
UINT uResolution, //以毫秒指定延时的精度,数值越小定时器事件分辨率越高。缺省值为1ms
LPTIMECALLBACK lpTimeProc, //指向一个回调函数
WORD dwUser, //存放用户提供的回调数据
UINT fuEvent )// 标志参数,TIME_ONESHOT:执行一次;TIME_PERIODIC:周期性执行

具体应用时,可以通过调用timeSetEvent()函数,将需要周期性执行的任务定义在 lpFunction回调函数中(如:定时采样、控制等),从而完成所需处理的事件。需要注意的是:任务处理的时间不能大于周期间隔时间。另外,在定时器使用完毕后,应及时调用timeKillEvent()将之释放。

原理:可以理解为代回调函数的timeGetTime

精度:毫秒,timeSetEvent可以通过timeBeginPeriod,timeEndPeriod设置定时器的最小解析精度, timeBeginPeriod,timeEndPeriod必须成对出现。

9:高精度时控函数QueryPerformanceFrequency,QueryPerformanceCounter

使用:

LARGE_INTEGER m_nFreq;  
LARGE_INTEGER m_nBeginTime;  
LARGE_INTEGER nEndTime;  
QueryPerformanceFrequency(&m_nFreq); // 获取时钟周期  
QueryPerformanceCounter(&m_nBeginTime); // 获取时钟计数  
Sleep(100);  
QueryPerformanceCounter(&nEndTime);  
cout << (nEndTime.QuadPart-m_nBeginTime.QuadPart)*1000/m_nFreq.QuadPart << endl;  

原理:CPU上也有一个计数器,以机器的clock为单位,可以通过rdtsc读取,而不用中断,因此其精度与系统时间相当。

精度:计算机获取硬件支持,精度比较高,可以通过它判断其他时间函数的精度范围。

10小结:

以上提到常用的9种时间函数,由于他们的用处不同,所以他们的精度也不尽相同,所以如果简单的延时可以用Sleep函数,稍微准确的延时可以使用clock函数,GetTickCount函数,更高级的实用timeGetTime函数;简单的定时事件可以用Timer,准确地可以用timeSetEvent;或取一般系统时间可以通time,或者CTime,或者COleDateTime,获取准确的时间可以用clock,或者GetTickCount函数,或者timeGetTime函数,而获取准确地系统时间要使用硬件支持的QueryPerformanceFrequency函数,QueryPerformanceCounter函数。

11 一段简单的代码来实现精度试验

[cpp] view plaincopy
int main()  
{  
      // 初始化代码  
      ......  
      int i = 0;  
      while(i++ < 1000)  
      {  
             // 获取时间代码  
             ......  
             printf(...); // 将时间打出  
      }  
}

通过结果可以看出Sleep, GetTickCount都是10~35ms左右的时间跳跃,timeGetTime为1ms,QueryPerformanceCounter和QueryPerformanceFrequency根据CPU频率计时,可以到100ns。
说明Windows中常用的计时函数中,标准计时函数(Sleep, GetTickCount)精度100ms, 多媒体时钟timeGetTime精度1ms,系统晶振大概可以到1us或100ns左右。

可以用来做定时器的计时函数一般都在标准计时的精度范围(CreateWaitableTimer),只有多媒体时钟定时器要高一些。如果想要更高精度的定时器,目前看来Windows没有提供,但是,我们可以通过开发更底层的驱动来获得应用层的高精度定时器,大概可以精确到10us~100us

<think>好的,用户想找一个用C语言编写的示例程序来测量其他程序的执行时间。首先,我需要回忆C语言中常用的时间测量方法。根据提供的引用,有几个可能的方案。 引用[1]提到了使用clock()函数,但指出它在C++中被弃用,不过C语言中可能还在使用。示例代码里展示了如何用clock_t和CLOCKS_PER_SEC来计算CPU时间。这个方法可能适合测量程序中的某段代码的CPU时间,而不是实际经过的墙上时间。需要注意,clock()测量的是处理器时间,所以如果程序中有sleep或者多线程,可能不准确。 引用[2]提到了clock_gettime函数,使用CLOCK_MONOTONIC参数。这应该是POSIX标准中的函数,可以提供更精确的时间测量。不过需要检查系统是否支持,因为可能不是所有平台都可用。 引用[3]提到Windows API中的GetMseconds,但用户可能更希望跨平台的解决方案,所以可能需要区分不同的系统环境。 引用[4]中的time命令是在shell中使用的,用户需要的是在C程序内部测量其他程序的执行时间,而不是外部命令,所以这个可能不适用。 引用[5]提到程序加载到内存的时间,可能和测量执行时间关系不大,但需要考虑程序启动的开销。 用户的需求是测量其他程序的执行时间,所以可能需要使用系统调用启动另一个进程,并记录开始和结束的时间。比如在C中使用system()函数或者fork/exec来运行目标程序,并在调用前后获取时间。 接下来,我需要综合这些信息,写出示例代码。可能有两种情况:一种是测量当前进程中某段代码的执行时间,另一种是测量外部程序的执行时间。用户的问题更可能是后者,但需要确认。 如果用户想测量另一个程序整体的执行时间,可能需要使用系统命令执行该程序,并记录开始和结束的墙上时间。这时候,clock()可能不太适合,因为它测量的是CPU时间,而执行外部程序可能涉及等待I/O等,墙上时间更准确。因此,可能需要使用time()函数或者gettimeofday(),但这两个函数在精度上有区别。或者使用clock_gettime(),如引用[2]中的例子。 考虑到跨平台性,time()函数返回秒级精度,可能不够精确。gettimeofday()可以提供微秒级,但已经被弃用,而clock_gettime()是更现代的替代,但可能在Windows上不可用。Windows下可能需要使用GetTickCountQueryPerformanceCounter。 不过用户可能希望一个通用的C示例,所以可以给出两种方案:一种使用clock(),另一种使用clock_gettime(),并注明平台差异。 根据引用[1]中的示例,测量当前进程中的代码段,而如果要测量外部程序,可能需要执行该程序并记录时间。例如,使用system()函数调用外部程序,并计算执行前后的时间差。 但需要注意的是,system()会启动一个shell来执行命令,可能有额外的开销。如果用户需要更精确地测量子进程的执行时间,可能需要使用fork和exec函数族,并在父进程中记录时间。 综上,示例代码可能需要分为两种情况:测量当前代码段的时间,或者测量外部程序时间。用户的问题可能更倾向于后者,所以需要给出如何执行外部程序并测量其执行时间的代码。 例如,使用clock_gettime()在启动子进程前后获取时间计算差值。或者使用time()函数,但精度较低。 现在,需要结合引用中的信息,编写示例代码。比如,引用[1]中的代码展示了使用clock()测量循环的时间,但用户需要测量的是其他程序,可能需要执行外部命令。例如: 使用system()调用外部程序,并在前后使用clock_gettime()来获取时间。 但需要注意,system()的执行时间包括启动shell和执行程序时间,这可能引入误差。因此,如果用户需要精确测量,可能需要使用更底层的进程创建方法,如fork和exec,并在父进程中记录时间。 不过,对于示例代码来说,可能简单使用system()结合时间函数会更易懂。因此,可以提供一个示例,使用clock_gettime()来测量执行外部命令的时间,并注明可能的误差来源。 另外,需要确认引用的正确性,引用[2]中的代码片段提到了clock_gettime(CLOCK_MONOTONIC, &ts1); fun();,这可能是在测量当前进程中函数的执行时间,而不是外部程序。因此,如果用户需要测量外部程序,可能需要不同的方法。 总结步骤: 1. 确定用户需求是测量当前程序中的代码段还是外部程序。 2. 根据需求选择合适的函数,如clock()、clock_gettime()或system() + 时间函数。 3. 编写示例代码,并解释代码的工作原理。 4. 提醒用户不同方法的优缺点,如精度、平台依赖性等。 根据用户的问题描述,他们想“测量其他程序的执行时间”,所以可能需要执行该程序并测量其整体的运行时间。因此,示例代码可能使用system()来调用该程序,并测量执行该命令前后的时间差。 例如,使用clock_gettime()在调用system()前后记录时间,并计算差值。但需要注意,clock_gettime()需要链接-lrt库,在Linux下可能需要。 示例代码可能如下: #include <stdio.h> #include <time.h> #include <stdlib.h> int main() { struct timespec start, end; clock_gettime(CLOCK_MONOTONIC, &start); // 执行外部程序 system("./my_program"); clock_gettime(CLOCK_MONOTONIC, &end); double time_taken = (end.tv_sec - start.tv_sec) + (end.tv_nsec - start.tv_nsec) / 1e9; printf("执行时间: %.6f秒\n", time_taken); return 0; } 但需要检查系统是否支持CLOCK_MONOTONIC,并且编译时可能需要加上-lrt参数,如gcc program.c -o program -lrt。 另外,引用[1]中的示例使用clock(),但该函数测量的是CPU时间,而不是墙上时间,所以如果外部程序有I/O等待,可能不准确。因此,墙上时间更适合这种情况。 此外,引用[4]提到使用time命令,但用户希望用C程序实现,所以需要避免依赖外部命令。 因此,总结可能的解决方案: 1. 使用clock_gettime()测量墙上时间,适用于Linux/Unix系统。 2. 使用GetTickCountQueryPerformanceCounterWindows下。 3. 使用clock()函数,但注意其测量的是CPU时间。 根据用户的问题,可能更倾向于跨平台的C代码,但现实中需要区分系统。因此,可能需要给出两种示例,或者注明平台限制。 最终,给出一个使用clock_gettime()的示例,并说明其在Linux下的使用,同时提到Windows的替代方法,如引用[3]中的GetMseconds。</think>### C语言测量程序执行时间的实现方法 #### 方法1:使用`clock()`函数(适合代码片段测量) ```c #include <stdio.h> #include <time.h> int main() { clock_t start = clock(); // 被测量的代码/程序 system("./your_program"); // 执行外部程序 clock_t end = clock(); double cpu_time = ((double)(end - start)) / CLOCKS_PER_SEC; printf("CPU时间: %.4f秒\n", cpu_time); return 0; } ``` **特点**: - 测量CPU时间而非实际经过时间 - 适合计算密集型任务 - Windows/Linux通用[^1] #### 方法2:使用`clock_gettime()`(高精度墙上时钟) ```c #include <stdio.h> #include <time.h> #include <stdlib.h> int main() { struct timespec start, end; clock_gettime(CLOCK_MONOTONIC, &start); system("./your_program"); // 执行外部程序 clock_gettime(CLOCK_MONOTONIC, &end); double elapsed = (end.tv_sec - start.tv_sec) + (end.tv_nsec - start.tv_nsec) * 1e-9; printf("实际执行时间: %.6f秒\n", elapsed); return 0; } ``` **编译指令**: ```bash gcc program.c -o program -lrt # Linux需要链接rt库 ``` **特点**: - 纳秒级精度 - 测量实际经过时间(墙上时钟) - 仅适用于Linux系统[^2] #### 方法3:Windows API方案 ```c #include <windows.h> #include <stdio.h> int main() { DWORD start = GetTickCount(); system("your_program.exe"); DWORD duration = GetTickCount() - start; printf("执行时间: %lu毫秒\n", duration); return 0; } ``` **特点**: - 毫秒级精度 - 需要`Windows.h`头文件 - 直接使用系统API[^3]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值