我曾研究过Project Euler问题并决定添加时间,因此通过以下代码段添加timeit
到时间main()
(为方便起见,将全局存储RESULT
在 main()
中)
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 和设备驱动程序的组合。
在 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。