Насколько точен python time.sleep ()?


95

Я могу дать ему числа с плавающей запятой, например

time.sleep(0.5)

но насколько это точно? Если я дам это

time.sleep(0.05)

он действительно будет спать около 50 мс?

Ответы:


79

Точность функции time.sleep зависит от точности сна вашей базовой ОС. Для ОС, не работающих в реальном времени, таких как стандартная Windows, наименьший интервал, в течение которого вы можете спать, составляет около 10-13 мс. Я видел точный сон в течение нескольких миллисекунд с того времени, когда он превышал минимальные 10-13 мс.

Обновление: как упоминалось в документах, цитируемых ниже, обычно засыпают в цикле, который обязательно вернется в режим сна, если он вас разбудит рано.

Я также должен упомянуть, что если вы используете Ubuntu, вы можете опробовать ядро ​​псевдореального времени (с установленным патчем RT_PREEMPT), установив пакет ядра rt (по крайней мере, в Ubuntu 10.04 LTS).

РЕДАКТИРОВАТЬ: Ядра Linux исправления не в реальном времени имеют минимальный интервал сна, намного ближе к 1 мс, а затем к 10 мс, но он варьируется недетерминированным образом.


8
На самом деле ядра Linux уже довольно давно используют по умолчанию более высокую скорость тиков, поэтому «минимальный» спящий режим намного ближе к 1 мс, чем к 10 мс. Это не гарантируется - другая системная активность может сделать ядро ​​неспособным запланировать ваш процесс так быстро, как вы захотите, даже без конкуренции с процессором. Я думаю, это то, что ядра реального времени пытаются исправить. Но, если вам действительно не нужно поведение в реальном времени, простое использование высокой скорости тиков (настройка ядра HZ) даст вам негарантированный, но с высоким разрешением спящий режим в Linux без использования чего-либо особенного.
Гленн Мейнард,

1
Да, вы правы, я пробовал с Linux 2.6.24-24 и смог довольно близко подойти к частоте обновления 1000 Гц. В то время, когда я делал это, я также запускал код на Mac и Windows, поэтому я, вероятно, запутался. Я знаю, что Windows XP по крайней мере имеет тиковую скорость около 10 мс.
Джозеф Лизи,

В Windows 8 у меня чуть меньше 2
мсек

2
Кроме того, точность зависит не только от ОС, но и от того, что ОС делает как в Windows, так и в Linux, если они заняты чем-то более важным sleep()из документации «время приостановки может быть больше, чем запрошено произвольной суммой, из-за планирования другая деятельность в системе ».
markmnl

56

Люди совершенно правы в отношении различий между операционными системами и ядрами, но я не вижу гранулярности в Ubuntu, а в MS7 я вижу гранулярность 1 мс. Предлагая другую реализацию time.sleep, а не просто другую скорость тиков. Кстати, при более внимательном рассмотрении можно предположить, что в Ubuntu гранулярность составляет 1 мкс, но это связано с функцией time.time, которую я использую для измерения точности. Типичное поведение time.sleep для Linux и Windows в Python


6
Интересно, что Linux предпочел всегда спать немного дольше, чем требовалось, тогда как Microsoft выбрала противоположный подход.
jleahy

2
@jleahy - подход Linux имеет для меня смысл: сон - это действительно освобождение приоритета выполнения на некоторое время, после которого вы снова подчиняетесь воле планировщика (который может сразу или не может сразу запланировать вас для выполнения) .
Underrun

2
как вы получили результаты? Не могли бы вы предоставить исходный код? График выглядит как артефакт использования разных таймеров для измерения времени и сна (в принципе, вы даже можете использовать дрейф между таймерами как источник случайности ).
jfs

2
@JF Sebastian - Функция, которую я использовал, находится в socsci.ru.nl/wilberth/computer/sleepAccuracy.html . На третьем графике показан эффект, аналогичный тому, что вы видите, но только 1.
Wilbert

1
@JF Sebastian, я использую time.clock () в окнах
Уилберт,

26

Из документации :

С другой стороны, точность time()и sleep()лучше, чем их эквиваленты в Unix: время выражается как числа с плавающей запятой, time()возвращает наиболее точное доступное время (с использованием Unix, gettimeofday где это возможно) и sleep()принимает время с ненулевой дробью ( selectиспользуется Unix. чтобы реализовать это, где это возможно).

И более конкретно WRT sleep():

Приостановить выполнение на указанное количество секунд. Аргументом может быть число с плавающей запятой, чтобы указать более точное время сна. Фактическое время приостановки может быть меньше запрошенного, потому что любой пойманный сигнал завершит sleep()последующее выполнение процедуры улавливания этого сигнала. Кроме того, время приостановки может быть больше, чем запрошено произвольной величиной, из-за планирования других действий в системе.


1
Может ли кто-нибудь объяснить, что «потому что любой пойманный сигнал завершит sleep () после выполнения процедуры перехвата этого сигнала»? К каким сигналам это относится? Благодарность!
Диего Эрранц

1
Сигналы похожи на уведомления, которыми управляет ОС ( en.wikipedia.org/wiki/Unix_signal ), это означает, что если ОС уловила сигнал, sleep () завершится после обработки этого сигнала.
ArianJM

24

Вот мое продолжение ответа Уилберта: то же самое и для Mac OS X Yosemite, так как об этом пока особо не упоминалось.Режим сна Mac OS X Yosemite

Похоже, что большую часть времени он спит примерно в 1,25 раза больше времени, чем вы запрашиваете, а иногда спит от 1 до 1,25 раза больше времени, которое вы запрашиваете. Он почти никогда (~ два раза из 1000 образцов) спит значительно больше, чем в 1,25 раза больше времени, чем вы запрашиваете.

Также (не показано явно) соотношение 1,25, кажется, довольно хорошо сохраняется, пока вы не опуститесь ниже примерно 0,2 мс, после чего оно начинает становиться немного нечетким. Кроме того, фактическое время, кажется, устанавливается примерно на 5 мс дольше, чем вы запрашиваете, после того как запрошенное время превышает 20 мс.

Опять же, похоже, что это совершенно другая реализация sleep()в OS X, чем в Windows или любом другом ядре Linux, которое использовал Уилберт.


Не могли бы вы загрузить исходный код теста на github / bitbucket?
jfs

3
Я пробовал это на своей машине. Результат аналогичен ответу @ Wilbert .
jfs

Я предполагаю, что сам сон точен, но планирование Mac OS X недостаточно точно, чтобы обеспечить достаточно высокую скорость процессора, чтобы выход из спящего режима задерживался. Если точное время пробуждения важно, кажется, что сон следует установить в 0,75 раза больше фактически запрошенного, и проверять время после пробуждения и неоднократно спать все реже и реже до правильного времени.
Микко Ранталайнен

16

Почему ты не узнаешь:

from datetime import datetime
import time

def check_sleep(amount):
    start = datetime.now()
    time.sleep(amount)
    end = datetime.now()
    delta = end-start
    return delta.seconds + delta.microseconds/1000000.

error = sum(abs(check_sleep(0.050)-0.050) for i in xrange(100))*10
print "Average error is %0.2fms" % error

Для записи, я получаю ошибку около 0,1 мс на моем HTPC и 2 мс на моем ноутбуке, обе машины с Linux.


10
Эмпирическое тестирование даст вам очень узкое представление. На это влияет множество ядер, операционных систем и конфигураций ядра. Старые ядра Linux по умолчанию используют более низкую скорость тиков, что приводит к большей детализации. В реализации Unix внешний сигнал во время сна в любой момент отменит его, и другие реализации могут иметь аналогичные прерывания.
Гленн Мейнард,

6
Ну, конечно, эмпирическое наблюдение не подлежит передаче. Помимо операционных систем и ядер, на это влияет множество временных проблем. Если требуются гарантии жесткого реального времени, необходимо учитывать всю конструкцию системы, от оборудования до оборудования. Я нашел результаты актуальными, учитывая утверждения, что 10 мс - это минимальная точность. Я не дома в мире Windows, но большинство дистрибутивов Linux уже какое-то время используют ядра без тиков. С распространением многоядерных процессоров вполне вероятно, что расписание будет очень близко к таймауту.
Ants Aasma

4

Небольшая поправка, некоторые люди упоминают, что сон можно преждевременно прервать по сигналу. В документах 3.6 говорится:

Изменено в версии 3.5: функция теперь спит не менее секунд, даже если спящий режим прерывается сигналом, за исключением случаев, когда обработчик сигнала вызывает исключение ( объяснение см. В PEP 475 ).


3

Вы не можете ничего гарантировать относительно sleep (), за исключением того, что он, по крайней мере, будет делать все возможное, чтобы заснуть, пока вы ему сказали (сигналы могут убить ваш сон до того, как время истекло, и многое другое может заставить его работать длинный).

Конечно, минимум, который вы можете получить в стандартной настольной операционной системе, будет около 16 мс (детализация таймера плюс время до переключения контекста), но есть вероятность, что% отклонение от предоставленного аргумента будет значительным, когда вы пытаетесь спать на 10 миллисекунд.

Сигналы, другие потоки, содержащие GIL, планирование ядра, изменение скорости процессора и т. Д. - все это может нанести ущерб продолжительности вашего потока / процесса в режиме ожидания.


3
В документации указано иное:> Фактическое время приостановки может быть меньше запрошенного, потому что любой пойманный сигнал завершит sleep () после выполнения подпрограммы перехвата этого сигнала.
Гленн Мейнард,

Ах, справедливо, починил столб, хотя длительный сон () гораздо более вероятен, чем более короткий.
Ник Бастин,

1
Два с половиной года спустя ... документация все еще лежит. В Windows сигналы не завершают режим сна (). Проверено на Python 3.2, WinXP SP3.
Дэйв

Да, но сигналы, предупреждающие о переходе в спящий режим, необычны, например KILL, в документации также говорится: «Кроме того, время приостановки может быть больше, чем запрошено на произвольную величину, из-за планирования других действий в системе». что более типично.
markmnl

1
Singnals и Windows - это просто глупо. В Windows Python time.sleep () ожидает ConsoleEvent для захвата таких вещей, как Ctrl-C.
schlenk

1

если вам нужна более высокая точность или меньшее время сна, подумайте о создании своего собственного:

import time

def sleep(duration, get_now=time.perf_counter):
    now = get_now()
    end = now + duration
    while now < end:
        now = get_now()


0
def start(self):
    sec_arg = 10.0
    cptr = 0
    time_start = time.time()
    time_init = time.time()
    while True:
        cptr += 1
        time_start = time.time()
        time.sleep(((time_init + (sec_arg * cptr)) - time_start ))

        # AND YOUR CODE .......
        t00 = threading.Thread(name='thread_request', target=self.send_request, args=([]))
        t00.start()

Не используйте переменную для передачи аргумента sleep (), вы должны вставить вычисление непосредственно в sleep ()


И возвращение моего терминала

1 ───── 17: 20: 16.891 ────────────────────

2 ───── 17: 20: 18.891 ────────────────────

3 ───── 17: 20: 20.891 ─────────────────────

4 ───── 17: 20: 22.891 ────────────────────

5 ───── 17: 20: 24.891 ────────────────────

....

689 ─── 17: 43: 12.891 ─────────────────────

690 ─── 17: 43: 14.890 ─────────────────────

691 ─── 17: 43: 16.891 ─────────────────────

692 ─── 17: 43: 18.890 ─────────────────────

693 ─── 17: 43: 20.891 ─────────────────────

...

727 ─── 17: 44: 28.891 ─────────────────────

728 ─── 17: 44: 30.891 ─────────────────────

729 ─── 17: 44: 32.891 ─────────────────────

730 ─── 17: 44: 34.890 ─────────────────────

731 ─── 17: 44: 36.891 ─────────────────────


0
def test():
    then = time.time()  # get time at the moment
    x = 0
    while time.time() <= then+1:  # stop looping after 1 second
        x += 1
        time.sleep(0.001)  # sleep for 1 ms
    print(x)

В Windows 7 / Python 3.8 вернулся 1000 для меня, даже если я установил значение сна на0.0005

так что идеальный 1 мс

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.