You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何时间测量偶尔返回15.625ms倍数的重复值?如何消除?

解决C++ Sleep计时出现15.625ms重复值的问题

这个问题我太熟悉了——本质上是Windows系统定时器默认分辨率限制导致的,咱们一步步拆解:

为什么会出现15.625ms的重复值?

Windows传统系统定时器的默认分辨率是15.625ms(对应64Hz的系统时钟滴答)。Sleep()函数的精度完全依赖这个系统时钟:当你调用Sleep(1)时,系统并不会真的等1ms,而是会等到下一个时钟滴答触发,所以实际等待时间会被"对齐"到15.625ms的整数倍。这就导致你的小数值等待(比如1-15ms)都会返回接近15.625ms的结果,看起来像是重复值。

而且你提到减少后台进程没用,因为这个是系统级的定时器设置,和进程负载关系不大。

怎么解决这个问题?

1. 临时提升系统定时器分辨率

Windows提供了timeBeginPeriod()和timeEndPeriod()函数(需要链接winmm.lib),可以临时把系统定时器分辨率提升到1ms,这样Sleep()的精度就能大幅提升,避免出现固定倍数的偏差。

修改后的代码示例:

#include <iostream>
#include <chrono>
#include <windows.h>
#include <mmsystem.h>  // 引入timeBeginPeriod相关声明

#pragma comment(lib, "winmm.lib")  // 编译时链接winmm库

void stall(int milliseconds){
    auto start = std::chrono::high_resolution_clock::now();
    Sleep(milliseconds);
    auto finish = std::chrono::high_resolution_clock::now();
    std::cout << std::chrono::duration_cast<std::chrono::nanoseconds>(finish-start).count()/1000000.0 << " ms\n";
}

int main(){
    timeBeginPeriod(1);  // 将系统定时器分辨率设为1ms
    std::cout << "Begin\n";
    for (int i = 1; i < 100; i++){
        stall(i);
    }
    timeEndPeriod(1);  // 用完务必恢复默认分辨率,避免增加系统功耗
    return 0;
}

2. 用高精度等待替代Sleep

如果你不想修改系统全局的定时器设置,也可以用std::this_thread::sleep_for(需要包含<thread>头文件),它在Windows下内部会优先尝试使用高精度定时器,配合上面的分辨率提升效果会更好:

#include <thread>
// ...
std::this_thread::sleep_for(std::chrono::milliseconds(milliseconds));

注意事项

  • timeBeginPeriod会影响整个系统的时钟频率,用完一定要用timeEndPeriod恢复默认值,否则会让系统保持高频时钟滴答,增加不必要的功耗。
  • 即使提升了分辨率,也不能保证等待时间100%精准(系统调度可能有微小延迟),但完全可以解决你遇到的重复值问题。

内容的提问来源于stack exchange,提问作者Daniel Franklin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 07:06:41