我最初是在coderanch.com上询问此问题的,因此,如果您尝试过在这里为我提供帮助,谢谢,不要觉得有必要重复努力。但是,coderanch.com大多是Java社区,经过一些研究,这似乎是一个Windows问题,因此我和我的同事认为这可能是寻求帮助的更合适的地方。

我编写了一个简短的程序,该程序可以在Windows性能计数器上旋转直到经过33ms,或者调用Sleep(33)。前者没有表现出任何意想不到的效果,但后者似乎(不一致地)将随后的处理减慢了约40毫秒(要么如此,要么就这样长时间影响了性能计数器返回的值)。旋转或Sleep()之后,程序将调用例程runInPlace()旋转2ms,计算其查询性能计数器的次数,然后返回该数字。

通过旋转完成初始的33ms延迟时,runInPlace()的迭代次数通常约为25万(在我的Windows 10上为XPS-8700)。它可能有所变化,这可能是由于其他系统开销所致,但平滑度在250,000左右变化。

现在,当通过调用Sleep()完成初始延迟时,会发生一些奇怪的事情。许多对runInPlace()的调用返回的数字接近250,000,但是其中许多返回的数字接近50,000。同样,范围在50,000左右变化,相当平稳。但是,它显然是在求平均值,而在80,000到150,000之间几乎没有任何返回。如果我在每次延迟后100次而不是一次调用runInPlace(),它在第20次调用后就不会返回较小范围内的迭代次数。由于runInPlace()运行2ms,这意味着我观察到的行为在40ms后消失了。如果我让runInPlace()运行4ms而不是2ms,那么它在第10次调用后再也不会返回较小范围内的迭代次数,因此,行为又在40ms之后消失了(同样,如果runInPlace()仅运行1ms;该行为在第40次通话后消失了)。

这是我的代码:

#include "stdafx.h"
#include "Windows.h"

int runInPlace(int msDelay)
{
    LARGE_INTEGER t0, t1;
    int n = 0;

    QueryPerformanceCounter(&t0);

    do
    {
            QueryPerformanceCounter(&t1);
            n++;
    } while (t1.QuadPart - t0.QuadPart < msDelay);

    return n;
}

int _tmain(int argc, _TCHAR* argv[])
{
    LARGE_INTEGER t0, t1;
    LARGE_INTEGER frequency;
    int n;

    QueryPerformanceFrequency(&frequency);

    int msDelay = 2 * frequency.QuadPart / 1000;

    int spinDelay = 33 * frequency.QuadPart / 1000;

    for (int i = 0; i < 100; i++)
    {
        if (argc > 1)
            Sleep(33);
        else
        {
            QueryPerformanceCounter(&t0);

            do
            {
                    QueryPerformanceCounter(&t1);
            } while (t1.QuadPart - t0.QuadPart < spinDelay);
        }

        n = runInPlace(msDelay);
        printf("%d \n", n);
    }

    getchar();

    return 0;
}

这是使用Sleep()进行延迟时得到的典型输出:

56116
248936
53659
34311
233488
54921
47904
45765
31454
55633
55870
55607
32363
219810
211400
216358
274039
244635
152282
151779
43057
37442
251658
53813
56237
259858
252275
251099

这是我旋转以创建延迟时得到的典型输出:

276461
280869
276215
280850
188066
280666
281139
280904
277886
279250
244671
240599
279697
280844
159246
271938
263632
260892
238902
255570
265652
274005
273604
150640
279153
281146
280845
248277

谁能帮助我了解这种行为? (请注意,我已经在五台计算机上尝试了使用Visual C++ 2010 Express编译的该程序。它仅在我拥有的两台最快的计算机上显示此行为。)

最佳答案

听起来这是由于计算机不忙时(SpeedStep),CPU将以较低的时钟速度运行。当计算机空闲时(例如在 sleep 中),时钟速度将降低以降低功耗。在较新的CPU上,此速度可以为所列时钟速度的35%或更小。一旦计算机再次变得忙碌,在CPU再次加速之前会有一个很小的延迟。

您可以关闭此功能(在BIOS中或通过将电源计划的高级设置中“处理器电源管理”下的“最小处理器状态”设置更改为100%)。

10-08 01:07