Неточное time.sleep() с Python 3.x и Windows 7
Исходя из этого поста, я определил нефункциональную реализацию функции Python time.sleep() в Windows 7 (Enterprise, 64-bit и 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()
Согласно этому примеру, этот скрипт должен выдавать выходные частоты примерно 60 Гц. Однако при запуске на моем компьютере с Windows 7 Enterprise эти выходные частоты я получаю для данной входной частоты:
Вход: 10 Гц - Выход: 9,15 Гц
Вход: 20 Гц - Выход: 16,03 Гц
Вход: 30 Гц - Выход 21,37 Гц
Диапазон входного сигнала: 40 Гц - 64 Гц - Выход: 32,05 Гц
Диапазон входного сигнала: 65 Гц - 10 кГц + - Выход: 64,10 Гц
Что здесь происходит? Почему переменные входные частоты (выше 40 Гц) дают одинаковую выходную частоту? Почему верхний предел выходной частоты составляет 64,10 Гц, даже если входная частота превышает 10000 Гц? Я не верю, что это проблема с разрешением time.sleep() на частоте ~60 Гц. Те же значения входной частоты, что и сценарий ideone.com, дают ожидаемые выходные частоты, поэтому они должны быть связаны с моим компьютером.
1 ответ
Python дает очень мало гарантий того, как эти вызовы будут себя вести, особенно кроссплатформенные. Здесь есть две вещи, которые могут пойти не так - time.time()
разрешение хуже, чем разрешение, которое вы пытаетесь достичь или sleep
разрешение есть.
На последних платформах сон должен быть примерно на 1-2 мс точнее, как указано здесь:
Насколько точным является python time.sleep()?
Это оставляет time.time()
, Документация для этого конкретного вызова предупреждает, что точность может быть низкой:
Обратите внимание, что хотя время всегда возвращается как число с плавающей запятой, не все системы предоставляют время с большей точностью, чем 1 секунда. Хотя эта функция обычно возвращает неубывающие значения, она может вернуть более низкое значение, чем предыдущий вызов, если системные часы были установлены обратно между двумя вызовами.
К счастью, API часов с более высоким разрешением предоставляется в time.perf_counter()
который пытается получить доступ к часам самого высокого разрешения, доступным на платформе. Из документации:
Возвращает значение (в долях секунды) счетчика производительности, то есть часов с наибольшим доступным разрешением для измерения короткой длительности. Он включает время, прошедшее во время сна, и является общесистемным. Контрольная точка возвращаемого значения не определена, поэтому допустима только разница между результатами последовательных вызовов.
В случае с Windows это, кажется, лучше, чем 60 Гц, что исправляет вашу проблему.