timeit 偶尔返回负值,timeit 中可能存在错误

Gar*_*ker 1 python time

我曾研究过Project Euler问题并决定添加时间,因此通过以下代码段添加timeit到时间main()(为方便起见,将全局存储RESULTmain()中)

t = timeit.timeit(main, 'gc.enable()', number=1)
print("# Euler", PROBLEM, ".py RESULT: ", RESULT))
Run Code Online (Sandbox Code Playgroud)

工作正常。但是,有些人跑得太快了,我以为我可以做到这一点。

t = timeit.timeit(main, 'gc.enable()', number=1)
if (t < 0.001):
    t2 = timeit.timeit(main, 'gc.enable()', number=1000)
Run Code Online (Sandbox Code Playgroud)

它有时有效。但是,如果我反复运行它,我有时会得到 t2 的负值。例如,使用 Euler #2,我通过连续运行 5 次得到这些结果。

# Euler2.py RESULT: 4613732  3.17869758716347e-05 seconds
repeats timing  -3.7966224778973e-05 sec per call

# Euler2.py RESULT: 4613732  3.1558464885145785e-05 seconds
repeats timing  2.4836235955056177e-05 sec per call

# Euler2.py RESULT: 4613732  3.131149340411519e-05 seconds
repeats timing  -3.5684903805855466e-05 sec per call

# Euler2.py RESULT: 4613732  3.177450256451194e-05 seconds
repeats timing  2.4558941864410162e-05 sec per call

# Euler2.py RESULT: 4613732  3.158939868681022e-05 seconds
repeats timing  2.4268726425449536e-05 sec per call
Run Code Online (Sandbox Code Playgroud)

现在,如果我将重复计数更改为 100,000 或更多,我根本看不到负 t2 值,并且每次调用的时间始终在 2.4e-5 秒左右。

如果我重复 10,000 次,我会看到新的行为。t2 始终为正值,但值会反弹很多。对于 10 次运行,我得到

repeats timing  2.4194581894745244e-05 sec per call
repeats timing  1.8200670315524775e-05 sec per call
repeats timing  2.4408832248987168e-05 sec per call
repeats timing  2.4378118077314547e-05 sec per call
repeats timing  1.8361976570139902e-05 sec per call
repeats timing  1.8055080028738498e-05 sec per call
repeats timing  1.8102133534236732e-05 sec per call
repeats timing  2.4485323058654477e-05 sec per call
repeats timing  3.118363087991698e-05 sec per call
repeats timing  1.803846408685413e-05 sec per call
Run Code Online (Sandbox Code Playgroud)

最后,将重复计数设置为 1000 并删除初始(repeat=1)timeit。结果的同一时间,一些负面影响和大量反弹。

我使用 Python 2.7 重复了这个集合,结果相似——其他的都是 3.4 版

对我来说,当总时间与系统计时器中断的顺序相同时,这看起来像是 timeit 功能中的一个错误,但我想也许我错过了一些东西。

添加

我还应该补充一点,我了解其他计时器功能,包括 perf_counter()。

我特别询问 timeit() 是因为我认为它是一个易于使用的 hi-hres 计时器,我可以在新版本和旧版本的 python 中使用,如果可以信任,我希望继续这样做。

添加

根据提供的答案,我将计时代码更改为 pef_counter() 上的 bsaed,果然,有时我也会得到负值。因此,如果您在旧窗口框上使用,小的时间增量根本不可靠。这就是我想知道的。让我觉得它在 Python 堆栈中的是,对于非常小的时间,这些值似乎是准确的。应该猜到是 Windows 和设备驱动程序的组合。

Ros*_*dge 5

在 Windows 上, timeit 默认time.clock用作其时间源,而后者又使用 Windows API QueryPerformanceCounter。根据 Windows 的版本和机器的功能,QueryPerformanceCounter使用处理器的时间戳计数器 (TSC) 作为计时器。许多较旧的多处理器机器无法在处理器之间保持 TSC 同步,并且没有将其正确报告给 Windows,或者有错误试图这样做。这导致QueryPerformanceCounter返回的结果随着进程在不同的处理器上执行而出现跳跃。

Microsoft 在 MSDN 上对该问题有很长的详细描述:http : //msdn.microsoft.com/en-us/library/windows/desktop/dn553408( v= vs.85).aspx

AMD 在 Windows XP 系统上发布了针对此问题的修复程序,称为AMD Dual Core Optimizer