关于c#:秒表似乎在紧密循环的迭代之间跳跃500μs


Stopwatch appears to jump 500μs between iterations of a tight loop

我写了一些代码,用一个紧密的循环来监视秒表的输出。此循环跟踪自上次迭代以来经过的刻度数。我观察到每秒跳跃500微秒20次,而大多数其他的迭代时间都小于1微秒。

有人能解释我为什么看到这些跳跃吗?

我试过了:

  • 设置处理器关联(无效)
  • 更改线程优先级(最高/高于正常值会使情况更糟)
  • 在调试器外部运行
  • 通过优化发布构建
  • 我的代码如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
            Stopwatch sw = new Stopwatch();
            int crossThresholdCount = 0;
            long lastElapsedTicks = 0;
            long lastPrintTicks = 0;
            Console.WriteLine("IsHighResolution:" + Stopwatch.IsHighResolution);
            Console.WriteLine("Frequency:" + Stopwatch.Frequency);

            sw.Start();

            long thresholdTicks = 5000;  // 10000 ticks per ms
            while (true)
            {
                long tempElapsed = sw.ElapsedTicks;
                long sincePrev = tempElapsed - lastElapsedTicks;
                lastElapsedTicks = tempElapsed;

                if (sincePrev > thresholdTicks)
                    crossThresholdCount++;

                // print output
                if (crossThresholdCount > 0 && tempElapsed - lastPrintTicks > TimeSpan.TicksPerSecond)
                {
                    lastPrintTicks = tempElapsed;
                    Console.WriteLine("crossed" + crossThresholdCount +" times");
                    crossThresholdCount = 0;
                }
            }


    很可能您看到了抢占式任务切换。这是操作系统挂起程序,然后执行其他程序的时间。这就是自Windows95以来的情况(Win3.1和更早的版本有协作式多任务处理,您可以根据需要保持CPU的时间)。

    顺便说一下,有一种更好的方法可以精确地计算执行时间:QueryThreadCycleTime,它只计算代码执行时的CPU周期,因此不包括这种暂停。


    你的测试没有真正意义…您的进程不是在您的计算机上运行的唯一进程。系统依次为每个线程提供处理器时间,因此在某些时间段内循环根本不运行,这就解释了"跳转"。