热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

时间的函数Sleep,clock,GetTickCount,QueryPerformanceCounter

介绍我们在衡量一个函数运行时间,或者判断一个算法的时间效率,或者在程序中我们需要一个定时器,定时执行一个特定的操作,比如在多

介绍

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

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

    精度&#xff1a;秒级别

5&#xff1a;C语言下的时钟周期clock()

    使用&#xff1a;   

clock_t start &#61; clock();
Sleep(100);
clock_t end &#61; clock();
double d &#61; (double)(start - end) / CLOCKS_PER_SEC;

    原理&#xff1a;clock()是获取计算机启动后的时间间隔。

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

6&#xff1a;Windows下的GetTickCount()

    使用&#xff1a;  

DWORD start &#61; GetTickCount();
Sleep(100);
DWORD end &#61; GetTickCount();

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

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

7&#xff1a;Windows下timeGetTime

    使用&#xff1a;需要包含Mmsystem.h&#xff0c;Windows.h&#xff0c;加入静态库Winmm.lib.

timeBeginPeriod(1);
DWORD start &#61; timeGetTime();
Sleep(100);
DWORD end &#61; timeGetTime();
timeEndPeriod(1);

    原理&#xff1a;timeGetTime也时常用于多媒体定时器中&#xff0c;可以通过查询进行定时。通过查询进行定时&#xff0c;本身也会影响定时器的定时精度。

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

8&#xff1a;windows下的timeSetEvent

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

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

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

    原理&#xff1a;可以理解为代回调函数的timeGetTime

    精度&#xff1a;毫秒&#xff0c;timeSetEvent可以通过timeBeginPeriod&#xff0c;timeEndPeriod设置定时器的最小解析精度, timeBeginPeriod,timeEndPeriod必须成对出现。
9&#xff1a;高精度时控函数QueryPerformanceFrequency&#xff0c;QueryPerformanceCounter

    使用&#xff1a;

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 <     原理&#xff1a;CPU上也有一个计数器&#xff0c;以机器的clock为单位&#xff0c;可以通过rdtsc读取&#xff0c;而不用中断&#xff0c;因此其精度与系统时间相当。

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

10小结&#xff1a;

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

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

int main()
{// 初始化代码......int i &#61; 0;while(i&#43;&#43; <1000){// 获取时间代码......printf(...); // 将时间打出}
}

通过结果可以看出Sleep, GetTickCount都是10~35ms左右的时间跳跃,timeGetTime为1ms,QueryPerformanceCounter和QueryPerformanceFrequency根据CPU频率计时&#xff0c;可以到100ns。

说明Windows中常用的计时函数中&#xff0c;标准计时函数&#xff08;Sleep&#xff0c; GetTickCount&#xff09;精度100ms&#xff0c; 多媒体时钟timeGetTime精度1ms&#xff0c;系统晶振大概可以到1us或100ns左右。

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



推荐阅读
  • linux进阶50——无锁CAS
    1.概念比较并交换(compareandswap,CAS),是原⼦操作的⼀种,可⽤于在多线程编程中实现不被打断的数据交换操作࿰ ... [详细]
  • 深入理解Java虚拟机的并发编程与性能优化
    本文主要介绍了Java内存模型与线程的相关概念,探讨了并发编程在服务端应用中的重要性。同时,介绍了Java语言和虚拟机提供的工具,帮助开发人员处理并发方面的问题,提高程序的并发能力和性能优化。文章指出,充分利用计算机处理器的能力和协调线程之间的并发操作是提高服务端程序性能的关键。 ... [详细]
  • 阿,里,云,物,联网,net,core,客户端,czgl,aliiotclient, ... [详细]
  • 本文介绍了基于c语言的mcs51单片机定时器计数器的应用教程,包括定时器的设置和计数方法,以及中断函数的使用。同时介绍了定时器应用的举例,包括定时器中断函数的编写和频率值的计算方法。主函数中设置了T0模式和T1计数的初值,并开启了T0和T1的中断,最后启动了CPU中断。 ... [详细]
  • C++字符字符串处理及字符集编码方案
    本文介绍了C++中字符字符串处理的问题,并详细解释了字符集编码方案,包括UNICODE、Windows apps采用的UTF-16编码、ASCII、SBCS和DBCS编码方案。同时说明了ANSI C标准和Windows中的字符/字符串数据类型实现。文章还提到了在编译时需要定义UNICODE宏以支持unicode编码,否则将使用windows code page编译。最后,给出了相关的头文件和数据类型定义。 ... [详细]
  • 本文讨论了clone的fork与pthread_create创建线程的不同之处。进程是一个指令执行流及其执行环境,其执行环境是一个系统资源的集合。在调用系统调用fork创建一个进程时,子进程只是完全复制父进程的资源,这样得到的子进程独立于父进程,具有良好的并发性。但是二者之间的通讯需要通过专门的通讯机制,另外通过fork创建子进程系统开销很大。因此,在某些情况下,使用clone或pthread_create创建线程可能更加高效。 ... [详细]
  • Java在运行已编译完成的类时,是通过java虚拟机来装载和执行的,java虚拟机通过操作系统命令JAVA_HOMEbinjava–option来启 ... [详细]
  • OO第一单元自白:简单多项式导函数的设计与bug分析
    本文介绍了作者在学习OO的第一次作业中所遇到的问题及其解决方案。作者通过建立Multinomial和Monomial两个类来实现多项式和单项式,并通过append方法将单项式组合为多项式,并在此过程中合并同类项。作者还介绍了单项式和多项式的求导方法,并解释了如何利用正则表达式提取各个单项式并进行求导。同时,作者还对自己在输入合法性判断上的不足进行了bug分析,指出了自己在处理指数情况时出现的问题,并总结了被hack的原因。 ... [详细]
  • Android工程师面试准备及设计模式使用场景
    本文介绍了Android工程师面试准备的经验,包括面试流程和重点准备内容。同时,还介绍了建造者模式的使用场景,以及在Android开发中的具体应用。 ... [详细]
  • 本文介绍了操作系统的定义和功能,包括操作系统的本质、用户界面以及系统调用的分类。同时还介绍了进程和线程的区别,包括进程和线程的定义和作用。 ... [详细]
  • Linux下安装免费杀毒软件ClamAV及使用方法
    本文介绍了在Linux系统下安装免费杀毒软件ClamAV的方法,并提供了使用该软件更新病毒库和进行病毒扫描的指令参数。同时还提供了官方安装文档和下载地址。 ... [详细]
  • 本文介绍了Java虚拟机中的垃圾收集器,包括年轻代收集器Serial收集器、ParNew收集器、Parallel Scavenge收集器,以及老年代收集器Serial Old收集器、Parallel Old收集器和CMS收集器。对每种收集器的算法和特点进行了详细解析,希望对读者有参考价值。 ... [详细]
  • 一次上线事故,30岁+的程序员踩坑经验之谈
    本文主要介绍了一位30岁+的程序员在一次上线事故中踩坑的经验之谈。文章提到了在双十一活动期间,作为一个在线医疗项目,他们进行了优惠折扣活动的升级改造。然而,在上线前的最后一天,由于大量数据请求,导致部分接口出现问题。作者通过部署两台opentsdb来解决问题,但读数据的opentsdb仍然经常假死。作者只能查询最近24小时的数据。这次事故给他带来了很多教训和经验。 ... [详细]
  • 本文讲述了作者从最初对软件工程的选择迷茫到逐渐喜欢并坚持学习的经历。作者在大学期间通过学习专业课和参与项目开发,不断挑战自己并取得成就感。虽然曾考虑过转专业和复读,但最终决定坚持学习软件工程,并为自己的未来努力奋斗。作者还提到了大学生活与自己最初的预期不同,但对此并没有太多抱怨。 ... [详细]
  • 本文介绍了GTK+中的GObject对象系统,该系统是基于GLib和C语言完成的面向对象的框架,提供了灵活、可扩展且易于映射到其他语言的特性。其中最重要的是GType,它是GLib运行时类型认证和管理系统的基础,通过注册和管理基本数据类型、用户定义对象和界面类型来实现对象的继承。文章详细解释了GObject系统中对象的三个部分:唯一的ID标识、类结构和实例结构。 ... [详细]
author-avatar
夕祈文_279
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有