Наскільки точним є час python.sleep ()?


95

Я можу дати йому числа з плаваючою комою, наприклад

time.sleep(0.5)

але наскільки це точно? Якщо я дам це

time.sleep(0.05)

чи справді він буде спати близько 50 мс?

Відповіді:


78

Точність функції 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 мс
markmnl

2
Також точність залежить не тільки від ОС, але і від того, що робить ОС як на Windows, так і на Linux, якщо вони зайняті чимось більш важливим sleep()із документів. "Час призупинення може бути довшим, ніж вимагається довільною сумою через планування інша діяльність у системі ".
markmnl

55

Люди цілком мають рацію щодо відмінностей між операційними системами та ядрами, але я не бачу деталізації в Ubuntu, а в MS7 я бачу деталізацію в 1 мс. Запропонуйте іншу реалізацію time.sleep, а не просто різну частоту галочок. Більш пильний огляд припускає, що в Ubuntu деталізація дорівнює 1 мкс, але це пов’язано з функцією time.time, яку я використовую для вимірювання точності. Типова поведінка сну в Linux та Windows у Python


6
Цікаво, як Linux вирішив завжди спати трохи довше, ніж просили, тоді як Microsoft обрала протилежний підхід.
jleahy

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

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

1
@JF Себастьян - Я використовував цю функцію в socsci.ru.nl/wilberth/computer/sleepAccuracy.html . Третій графік показує ефект, подібний до того, що ви бачите, але лише 1 ‰.
Вільберт

1
@JF Себастьян Я використовую time.clock () на вікнах
Вільберт

26

З документації :

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

А точніше wrt sleep():

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


1
Хто-небудь може пояснити "тому, що будь-який зловлений сигнал припиняє режим sleep () після виконання процедури лову цього сигналу"? До яких сигналів це стосується? Дякую!
Дієго Герранц

1
Сигнали схожі на повідомлення, якими керує ОС ( en.wikipedia.org/wiki/Unix_signal ), це означає, що якщо ОС захопила сигнал, сплячий режим () закінчується після обробки цього сигналу.
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

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

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

Сигнали, інші потоки, що утримують GIL, задоволення від планування ядра, швидкість процесора тощо тощо можуть зіпсувати хаос із часом, коли ваш потік / процес насправді спить.


3
У документації сказано інакше:> Фактичний час призупинення може бути меншим, ніж запитуваний, оскільки будь-який спійманий сигнал припиняє сплячий режим () після виконання процедури лову цього сигналу.
Гленн Мейнард,

Ах, справедливо, фіксували пост, хоча довше спати () набагато частіше, ніж коротше.
Нік Бастін,

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

Так, але сигнали попереднього виходу з режиму сну незвичні, наприклад, KILL, в документації також сказано: "Крім того, час призупинення може бути довшим, ніж вимагається довільною сумою через планування інших дій у системі." що є більш типовим.
markmnl

1
Сингнали та 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 ────────────────────

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.