time.sleep() Python 3.x 和 Windows 不准确 7
Inaccurate time.sleep() with Python 3.x and Windows 7
从 this post 开始,我在 Windows 下确定了 Python 的 time.sleep() 函数的非功能性实现7(企业版,64 位和 Python 3.4.4)。
这里是参考.py脚本:
import threading, time
def Return():
return
def Setup():
for _ in range(10):
time_before = time.time()
Return()
wait_delay = -time.time()
delays = []
InputFrequency = 60
while (time.time() - time_before) < (1 / InputFrequency):
time.sleep(0)
wait_delay += time.time()
delays.append(wait_delay)
print("Output frequency: " + str([1/t for t in delays][0]) + " Hz")
threading.Thread(target=Setup).start()
根据 this 示例,此脚本应产生大约 60Hz 的输出频率。然而,当 运行 在我的 Windows 7 Enterprise 机器上时,这些是我收到的给定输入频率的输出频率:
输入:10Hz - 输出:9.15Hz
输入:20Hz - 输出:16.03Hz
输入:30Hz - 输出 21.37Hz
输入范围:40Hz - 64Hz - 输出:32.05Hz
输入范围:65Hz - 10kHz+ - 输出:64.10Hz
这是怎么回事?为什么不同的输入频率(40Hz 以上)会产生相同的输出频率?为什么输入频率超过10000Hz,输出频率上限为64.10Hz?我不认为这是 ~60Hz 时的 time.sleep() 分辨率问题。提供给 ideone.com 脚本的相同输入频率值会产生预期的输出频率,因此它一定与我的计算机有关。
Python 很少保证这些调用的行为方式,尤其是跨平台的。这里有两件事可能会出错 - time.time()
的分辨率比您尝试达到的分辨率差,或者 sleep
的分辨率是。
在最近的平台上,睡眠应该大致准确至少 1 到 2 毫秒,如此处报道:
How accurate is python's time.sleep()?
剩下 time.time()
。此特定调用的文档警告准确性可能很差:
Note that even though the time is always returned as a floating point
number, not all systems provide time with a better precision than 1
second. While this function normally returns non-decreasing values, it
can return a lower value than a previous call if the system clock has
been set back between the two calls.
幸运的是,time.perf_counter()
中提供了更高分辨率的时钟 API,它尝试访问平台上可用的最高分辨率时钟。来自文档:
Return the value (in fractional seconds) of a performance counter,
i.e. a clock with the highest available resolution to measure a short
duration. It does include time elapsed during sleep and is
system-wide. The reference point of the returned value is undefined,
so that only the difference between the results of consecutive calls
is valid.
在 Windows 的情况下,这似乎比解决您的问题的 60Hz 更好。
从 this post 开始,我在 Windows 下确定了 Python 的 time.sleep() 函数的非功能性实现7(企业版,64 位和 Python 3.4.4)。
这里是参考.py脚本:
import threading, time
def Return():
return
def Setup():
for _ in range(10):
time_before = time.time()
Return()
wait_delay = -time.time()
delays = []
InputFrequency = 60
while (time.time() - time_before) < (1 / InputFrequency):
time.sleep(0)
wait_delay += time.time()
delays.append(wait_delay)
print("Output frequency: " + str([1/t for t in delays][0]) + " Hz")
threading.Thread(target=Setup).start()
根据 this 示例,此脚本应产生大约 60Hz 的输出频率。然而,当 运行 在我的 Windows 7 Enterprise 机器上时,这些是我收到的给定输入频率的输出频率:
输入:10Hz - 输出:9.15Hz
输入:20Hz - 输出:16.03Hz
输入:30Hz - 输出 21.37Hz
输入范围:40Hz - 64Hz - 输出:32.05Hz
输入范围:65Hz - 10kHz+ - 输出:64.10Hz
这是怎么回事?为什么不同的输入频率(40Hz 以上)会产生相同的输出频率?为什么输入频率超过10000Hz,输出频率上限为64.10Hz?我不认为这是 ~60Hz 时的 time.sleep() 分辨率问题。提供给 ideone.com 脚本的相同输入频率值会产生预期的输出频率,因此它一定与我的计算机有关。
Python 很少保证这些调用的行为方式,尤其是跨平台的。这里有两件事可能会出错 - time.time()
的分辨率比您尝试达到的分辨率差,或者 sleep
的分辨率是。
在最近的平台上,睡眠应该大致准确至少 1 到 2 毫秒,如此处报道:
How accurate is python's time.sleep()?
剩下 time.time()
。此特定调用的文档警告准确性可能很差:
Note that even though the time is always returned as a floating point number, not all systems provide time with a better precision than 1 second. While this function normally returns non-decreasing values, it can return a lower value than a previous call if the system clock has been set back between the two calls.
幸运的是,time.perf_counter()
中提供了更高分辨率的时钟 API,它尝试访问平台上可用的最高分辨率时钟。来自文档:
Return the value (in fractional seconds) of a performance counter, i.e. a clock with the highest available resolution to measure a short duration. It does include time elapsed during sleep and is system-wide. The reference point of the returned value is undefined, so that only the difference between the results of consecutive calls is valid.
在 Windows 的情况下,这似乎比解决您的问题的 60Hz 更好。