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

为何添加Thread.Sleep(1)会使Stopwatch计时结果相差一个数量级?

关于Stopwatch计时结果因Thread.Sleep(1)出现数量级差异的解惑

我在代码中遇到了Stopwatch的异常行为:在循环的计时逻辑外部添加Thread.Sleep(1)后,循环内的计时结果相差一个数量级。为此编写了测试程序复现问题,多次运行结果一致。尝试复用Stopwatch实例(调用Restart/Reset/Start),问题依然存在,不确定是线程问题还是Stopwatch本身的问题。

完整测试代码如下:

public static void DoStuff()
{
    long ticks;
    double seconds;

    ticks = Stopwatch.GetTimestamp();

    if (ticks % 2 == 0)
    {
        ticks = ticks / Stopwatch.Frequency;
    }
    else
    {
        seconds = ticks / Stopwatch.Frequency;
    }
}

static void Main(string[] args)
{
    const int loopCount = 1000;
    List<double> times;

    Console.WriteLine("Loops = " + loopCount);

    // No sleep
    times = new List<double>();
    for (int i = 0; i < loopCount; i++)
    {
        Stopwatch sw = Stopwatch.StartNew();
        DoStuff();
        sw.Stop();

        times.Add(sw.Elapsed.TotalSeconds);

        // Thread.Sleep(0);
    }

    Console.WriteLine();
    Console.WriteLine("--- No sleep ---");
    Console.WriteLine("Average = " + times.Average() + " s");
    Console.WriteLine("Average = " + (times.Average() * 1000000000).ToString("N2") + " ns");

    // Sleep
    times = new List<double>();
    for (int i = 0; i < loopCount; i++)
    {
        Stopwatch sw = Stopwatch.StartNew();
        DoStuff();
        sw.Stop();

        times.Add(sw.Elapsed.TotalSeconds);

        Thread.Sleep(1);
    }

    Console.WriteLine();
    Console.WriteLine("--- Sleep ---");
    Console.WriteLine("Average = " + times.Average() + " s");
    Console.WriteLine("Average = " + (times.Average() * 1000000000).ToString("N2") + " ns");

    Console.WriteLine();
    Console.Write("Press any key to continue...");
    Console.ReadKey();
}

问题原因解析

这不是Stopwatch的问题,而是CPU调度与缓存行为导致的测量上下文差异:

  • 无Sleep的循环场景:循环连续执行时,DoStuff的代码会被CPU的指令缓存、数据缓存完全命中,JIT编译器也会对这段高频执行的代码进行深度优化(比如内联、常量折叠),所以DoStuff的实际执行耗时是真正的纳秒级,Stopwatch记录的是精准的执行时间。
  • 添加Sleep(1)的场景:每次循环后的Thread.Sleep(1)会让当前线程主动放弃CPU,进入等待队列。当线程再次被调度唤醒时,CPU的缓存已经“冷”了——之前缓存的DoStuff指令和数据需要重新从内存加载,同时线程调度本身也有微秒级的开销。这些额外的缓存加载、调度开销都被Stopwatch计入了单次DoStuff的执行时间,最终导致计时结果比无Sleep的情况大一个数量级。

补充验证

你尝试复用Stopwatch实例后问题依然存在,这进一步证明问题不在Stopwatch本身——Stopwatch依赖硬件高精度计时器(如x86的RDTSC指令),本身精度极高且无状态污染。差异的核心在于两次测试中,DoStuff执行时的CPU环境完全不同:一个是热缓存、连续执行的高效环境,另一个是冷缓存、频繁调度的低效环境。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 15:05:10