Неточное 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 Гц, что исправляет вашу проблему.

Другие вопросы по тегам