时间的函数,sleep,clock,gettickcount,....

本文介绍了Windows环境下九种常用的时间函数,包括Sleep、MFC下的Timer事件、C语言下的Time、COM对象中的COleDateTime等,详细阐述了每种函数的使用方法、原理及精度,并对比了它们之间的差异。

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

介绍

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

       精度:秒级别

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

       使用:   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()

使用:  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.hWindows.h,加入静态库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函数。

<think>好的,我需要帮助用户理解他们提供的Lua代码,并解释时间补偿算法的应用。首先,用户提供了一段代码,涉及GetTickCount()Sleep函数和一个补偿公式。看起来这段代码的目的是在某个动作执行后,通过动态调整休眠时间来维持固定的执行间隔,可能用于游戏或实时系统中的帧率控制或定时任务。 首先,我要分析代码的结构。代码定义了一个全局变量last_tick,记录上一次的时间戳。函数CompensatedAction()获取当前时间current_tick,计算上一次的时间差delta。然后使用公式math.max(0, 15 - delta)来计算需要休眠的时间,确保每次执行的总时间(执行时间 + 休眠时间)至少为15毫秒。最后更新last_tick为当前时间。 接下来,我需要解释这段代码的工作原理。用户可能想知道这是如何实现时间补偿的,特别是在存在执行时间波动的情况下如何保持稳定间隔。例如,如果某次执行耗时5ms,那么休眠时间会是10ms,总共15ms;如果执行耗时20ms,休眠时间就是0ms,这样总间隔就是20ms,但可能无法维持固定频率,这里可能需要指出潜在的问题,比如当执行时间超过15ms时,间隔会拉长,导致不稳定。 用户可能的应用场景包括游戏循环、定时器任务或需要稳定频率的实时处理。需要举例说明代码如何被调用,比如在循环中不断执行CompensatedAction(),并执行具体的操作,如更新游戏状态或传感器数据。 同时,用户可能需要了解这段代码的优缺点。优点在于简单直接,适用于对时间精度要求不高的场景。缺点包括:当delta超过15ms时无法补偿,导致间隔时间延长;没有考虑系统休眠精度问题(比如Sleep函数精度可能不足);单次执行时间波动较大时可能导致累积误差。 用户可能还想知道如何改进这段代码。例如,可以引入更复杂的补偿机制,比如使用滑动窗口平均或PID控制来调整休眠时间,或者在delta超过阈值时进行警告或日志记录。此外,可以提到使用高精度计时器或调整补偿公式来适应不同场景的需求。 最后,需要确保解释清晰,结构合理,符合用户之前提供的格式,比如分步骤说明、代码示例、应用场景和优化建议。同时,要使用中文,避免使用Markdown格式,保持口语化,但又要专业准确。</think>以下是为您设计的带时间补偿机制的定时执行Lua代码实现,包含详细注释和应用说明: ```lua -- 获取系统毫秒计时函数(假设已存在环境提供) -- 实际开发中可能需要替换为具体平台的API,如os.time()*1000 local GetTickCount = os.clock() * 1000 -- 示例实现 -- 初始化时间记录器 local last_tick = GetTickCount() function CompensatedAction() -- 获取当前系统时间戳 local current_tick = GetTickCount() -- 计算实际耗时差值 local delta = current_tick - last_tick -- 动态补偿公式(目标周期15ms) -- 当实际耗时δt < 15ms时,补偿剩余时间 -- 当δt ≥15ms时立即执行(补偿量=0) local compensation = math.max(0, 15 - delta) -- 执行时间补偿(注意:实际Sleep精度取决于系统) Sleep(compensation) -- 假设存在毫秒级休眠函数 -- 更新基准时间戳(补偿后的当前时间) last_tick = GetTickCount() -- 此处添加实际业务逻辑 print("执行补偿动作,本次补偿量:"..compensation.."ms") end -- 使用示例:循环执行任务 while true do CompensatedAction() -- 实际业务逻辑示例: -- 1. 游戏中的固定帧率物理模拟 -- 2. 工业控制的定时信号采集 -- 3. 网络心跳包发送 end ``` ### 代码原理说明 1. **时间差值计算** - 通过$delta = current\_tick - last\_tick$计算实际间隔 - 当实际间隔小于目标周期(15ms)时,补偿剩余时间 - 当实际间隔超过目标周期时,立即执行下个周期 2. **补偿公式分析** $$ compensation = max(0, T_{target} - \Delta t) $$ 其中$T_{target}=15$ms为目标周期,$\Delta t$为实际耗时 3. **执行时序示意图** ``` |----动作执行----|补偿等待|----动作执行----| | δt=8ms | 7ms | δt=10ms | ``` ### 典型应用场景 1. **工业控制系统** - 温度采样周期稳定在15ms,即使某次采样耗时波动(如8ms→22ms) 2. **游戏物理引擎** - 保证角色运动计算每15ms执行一次,避免帧率波动导致的"时快时慢"现象 3. **高频交易系统** - 维持精确的报价刷新频率,避免因处理延迟导致的市场数据滞后 ### 优化建议 1. **统计异常波动** ```lua -- 添加超时报警机制 if delta > 20 then -- 超过阈值33% log_error("系统过载!实际间隔:"..delta.."ms") end ``` 2. **动态调整周期** ```lua -- 根据负载自动调整目标周期 local dynamic_target = 15 + (delta > 15 and 2 or 0) -- 超时后放宽要求 ``` 3. **高精度计时方案** ```lua -- 使用更高精度计时器(Windows平台示例) local GetTickCount = function() local freq = winapi.get_performance_frequency() local count = winapi.get_performance_counter() return count * 1000 / freq -- 转换为毫秒 end ``` 该算法通过反向补偿机制,在保持固定周期执行的同时,有效吸收单次执行时间的波动,适用于对周期稳定性要求高于绝对延时的场景。实际开发中需根据具体硬件性能调整目标周期参数。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值