Wie genau ist Pythons time.sleep ()?


94

Ich kann ihm Gleitkommazahlen geben, wie z

time.sleep(0.5)

aber wie genau ist es? Wenn ich es gebe

time.sleep(0.05)

Wird es wirklich etwa 50 ms schlafen?

Antworten:


77

Die Genauigkeit der time.sleep-Funktion hängt von der Schlafgenauigkeit Ihres zugrunde liegenden Betriebssystems ab. Für Nicht-Echtzeit-Betriebssysteme wie Standard-Windows beträgt das kleinste Intervall, in dem Sie schlafen können, etwa 10-13 ms. Ich habe innerhalb einiger Millisekunden nach dieser Zeit einen genauen Schlaf gesehen, wenn er über dem Minimum von 10-13 ms lag.

Update: Wie in den unten genannten Dokumenten erwähnt, ist es üblich, den Schlaf in einer Schleife durchzuführen, die sicherstellt, dass Sie wieder einschlafen, wenn Sie früh aufgeweckt werden.

Ich sollte auch erwähnen, dass Sie unter Ubuntu einen Pseudo-Echtzeit-Kernel (mit dem RT_PREEMPT-Patch-Set) ausprobieren können, indem Sie das RT-Kernel-Paket installieren (zumindest in Ubuntu 10.04 LTS).

BEARBEITEN: Korrektur Nicht-Echtzeit-Linux-Kernel haben ein Mindestschlafintervall, das viel näher bei 1 ms als 10 ms liegt, aber nicht deterministisch variiert.


8
Tatsächlich haben Linux-Kernel seit einiger Zeit standardmäßig eine höhere Tick-Rate verwendet, sodass der "minimale" Schlaf viel näher bei 1 ms als bei 10 ms liegt. Es ist nicht garantiert - andere Systemaktivitäten können dazu führen, dass der Kernel Ihren Prozess nicht so schnell planen kann, wie Sie möchten, auch ohne CPU-Konflikte. Das versuchen die Echtzeit-Kernel zu beheben, denke ich. Wenn Sie jedoch kein Echtzeitverhalten benötigen, können Sie durch einfache Verwendung einer hohen Tick-Rate (Kernel-HZ-Einstellung) unter Linux nicht garantierte, sondern hochauflösende Ruhezustände erzielen, ohne etwas Besonderes zu verwenden.
Glenn Maynard

1
Ja, Sie haben Recht, ich habe es mit Linux 2.6.24-24 versucht und konnte ziemlich nahe an 1000-Hz-Aktualisierungsraten kommen. Zu der Zeit, als ich das tat, habe ich den Code auch auf Mac und Windows ausgeführt, also war ich wahrscheinlich verwirrt. Ich weiß, dass Windows XP mindestens eine Tick-Rate von etwa 10 ms hat.
Joseph Lisee

Unter Windows 8 bekomme ich knapp 2ms
markmnl

2
Außerdem hängt die Genauigkeit nicht nur vom Betriebssystem ab, sondern auch davon, was das Betriebssystem sowohl unter Windows als auch unter Linux tut, wenn sie damit beschäftigt sind, etwas Wichtigeres sleep()aus den Dokumenten zu tun andere Aktivität im System ".
Markmnl

55

Die Leute haben völlig Recht mit den Unterschieden zwischen Betriebssystemen und Kerneln, aber ich sehe keine Granularität in Ubuntu und ich sehe eine Granularität von 1 ms in MS7. Schlagen Sie eine andere Implementierung von time.sleep vor, nicht nur eine andere Tickrate. Eine genauere Betrachtung deutet übrigens auf eine Granularität von 1 μs in Ubuntu hin, aber das liegt an der time.time-Funktion, die ich zum Messen der Genauigkeit verwende. Linux- und Windows-typisches time.sleep-Verhalten in Python


6
Es ist interessant, wie Linux sich dafür entschieden hat, immer etwas länger als gewünscht zu schlafen, während Microsoft den umgekehrten Ansatz gewählt hat.
Jleahy

2
@jleahy - der Linux-Ansatz macht für mich Sinn: Schlaf ist wirklich eine Freigabe der Ausführungspriorität für einen Zeitraum, nach dem Sie sich erneut dem Willen des Schedulers unterwerfen (der Sie möglicherweise sofort für die Ausführung einplanen kann oder nicht). .
Unterlauf

2
Wie haben Sie die Ergebnisse erhalten? Könnten Sie den Quellcode angeben? Das Diagramm sieht aus wie ein Artefakt der Verwendung verschiedener Timer zum Messen der Zeit und des Schlafes (im Prinzip können Sie sogar die Drift zwischen den Timern als Zufallsquelle verwenden ).
JFS

1
@JF Sebastian - Die Funktion, die ich verwendet habe, befindet sich in socsci.ru.nl/wilberth/computer/sleepAccuracy.html . Das dritte Diagramm dort zeigt einen ähnlichen Effekt wie Sie, jedoch nur 1 ‰.
Wilbert

1
@JF Sebastian Ich benutze time.clock () unter Windows
Wilbert

26

Aus der Dokumentation :

Andererseits ist die Genauigkeit von time()und sleep()besser als ihre Unix-Äquivalente: Zeiten werden als Gleitkommazahlen ausgedrückt, geben time()die genaueste verfügbare Zeit zurück (unter Verwendung von Unix, sofern gettimeofday verfügbar) und sleep()akzeptieren eine Zeit mit einem Bruchteil ungleich Null (Unix selectwird verwendet) um dies umzusetzen, sofern verfügbar).

Und insbesondere bzgl sleep():

Unterbrechen Sie die Ausführung für die angegebene Anzahl von Sekunden. Das Argument kann eine Gleitkommazahl sein, um eine genauere Ruhezeit anzuzeigen. Die tatsächliche Suspendierungszeit kann kürzer als die angeforderte sein, da jedes abgefangene Signal die sleep()folgende Ausführung der Abfangroutine dieses Signals beendet . Außerdem kann die Suspendierungszeit aufgrund der Planung anderer Aktivitäten im System länger sein als um einen beliebigen Betrag angefordert.


1
Kann jemand erklären, "weil ein abgefangenes Signal den sleep () nach Ausführung der Abfangroutine dieses Signals beendet"? Auf welche Signale bezieht es sich? Vielen Dank!
Diego Herranz

1
Signale sind wie Benachrichtigungen, die das Betriebssystem verwaltet ( en.wikipedia.org/wiki/Unix_signal ). Wenn das Betriebssystem ein Signal abfängt, ist sleep () nach der Behandlung dieses Signals beendet.
ArianJM

23

Hier ist meine Fortsetzung von Wilberts Antwort: Dasselbe gilt für Mac OS X Yosemite, da es noch nicht viel erwähnt wurde.Schlafverhalten von Mac OS X Yosemite

Es sieht so aus, als würde es die meiste Zeit ungefähr das 1,25-fache der von Ihnen angeforderten Zeit und manchmal das 1- bis 1,25-fache der von Ihnen angeforderten Zeit schlafen. Es schläft fast nie (~ zweimal von 1000 Proben) deutlich mehr als das 1,25-fache der von Ihnen gewünschten Zeit.

Auch (nicht explizit gezeigt) scheint die 1,25-Beziehung ziemlich gut zu halten, bis Sie unter etwa 0,2 ms kommen, wonach es anfängt, ein wenig unscharf zu werden. Darüber hinaus scheint sich die tatsächliche Zeit auf etwa 5 ms länger einzustellen, als Sie anfordern, nachdem die angeforderte Zeit über 20 ms liegt.

Auch hier scheint es sich um eine völlig andere Implementierung von sleep()OS X zu handeln als unter Windows oder dem Linux-Kern, den Wilbert verwendet hat.


Könnten Sie den Quellcode für den Benchmark auf github / bitbucket hochladen?
JFS

3
Ich habe es auf meinem Computer versucht . Das Ergebnis ähnelt der Antwort von @ Wilbert .
JFS

Ich würde vermuten, dass der Ruhezustand selbst korrekt ist, aber die Mac OS X-Planung ist nicht genau genug, um die CPU schnell genug bereitzustellen, sodass sich das Aufwecken aus dem Ruhezustand verzögert. Wenn eine genaue Aufwachzeit wichtig ist, sollte der Schlaf auf das 0,75-fache der tatsächlich angeforderten Zeit eingestellt werden. Überprüfen Sie die Zeit nach dem Aufwachen und schlafen Sie immer weniger bis zur richtigen Zeit.
Mikko Rantalainen

16

Warum findest du es nicht heraus:

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

Für die Aufzeichnung erhalte ich ungefähr 0,1 ms Fehler auf meinem HTPC und 2 ms auf meinem Laptop, beide Linux-Maschinen.


10
Empirische Tests geben Ihnen eine sehr enge Sicht. Es gibt viele Kernel, Betriebssysteme und Kernelkonfigurationen, die dies beeinflussen. Ältere Linux-Kernel verwenden standardmäßig eine niedrigere Tick-Rate, was zu einer höheren Granularität führt. In der Unix-Implementierung wird es durch ein externes Signal während des Ruhezustands jederzeit abgebrochen, und andere Implementierungen können ähnliche Unterbrechungen aufweisen.
Glenn Maynard

6
Natürlich ist die empirische Beobachtung nicht übertragbar. Abgesehen von Betriebssystemen und Kerneln gibt es viele vorübergehende Probleme, die dies betreffen. Wenn harte Echtzeitgarantien erforderlich sind, muss das gesamte Systemdesign von der Hardware an berücksichtigt werden. Ich fand gerade die Ergebnisse relevant, wenn man bedenkt, dass 10 ms die Mindestgenauigkeit sind. Ich bin in der Windows-Welt nicht zu Hause, aber die meisten Linux-Distributionen führen seit einiger Zeit tickless-Kernel aus. Da Multicores mittlerweile weit verbreitet sind, ist es ziemlich wahrscheinlich, dass sie kurz vor dem Timeout geplant werden.
Ameisen Aasma

4

Eine kleine Korrektur, mehrere Leute erwähnen, dass der Schlaf durch ein Signal vorzeitig beendet werden kann. In den 3.6-Dokumenten heißt es:

In Version 3.5 geändert: Die Funktion wird jetzt mindestens Sekunden lang in den Ruhezustand versetzt, selbst wenn der Ruhezustand durch ein Signal unterbrochen wird, es sei denn, der Signalhandler löst eine Ausnahme aus ( Begründung siehe PEP 475 ).


3

Sie können nicht wirklich etwas über Schlaf garantieren (), außer dass es zumindest die beste Anstrengung macht, zu schlafen, solange Sie es gesagt haben (Signale können Ihren Schlaf töten, bevor die Zeit abgelaufen ist, und viele andere Dinge können ihn zum Laufen bringen lange).

Sicherlich beträgt das Minimum, das Sie auf einem Standard-Desktop-Betriebssystem erreichen können, etwa 16 ms (Timer-Granularität plus Zeit bis zum Kontextwechsel), aber es besteht die Möglichkeit, dass die prozentuale Abweichung vom angegebenen Argument beim Versuch erheblich ist für 10s Millisekunden schlafen.

Signale, andere Threads, die die GIL enthalten, Spaß beim Planen des Kernels, Steigern der Prozessorgeschwindigkeit usw. können mit der Dauer, in der Ihr Thread / Prozess tatsächlich schläft, Chaos anrichten.


3
In der Dokumentation heißt es anders:> Die tatsächliche Suspendierungszeit kann kürzer sein als die angeforderte, da jedes abgefangene Signal den sleep () nach Ausführung der Abfangroutine dieses Signals beendet.
Glenn Maynard

Ah fairer Punkt, habe den Beitrag behoben, obwohl es viel wahrscheinlicher ist, länger zu schlafen () als kürzere.
Nick Bastin

1
Zweieinhalb Jahre später ... liegt die Dokumentation immer noch. Unter Windows beenden Signale den Ruhezustand nicht (). Getestet auf Python 3.2, WinXP SP3.
Dave

Ja, aber Signale, die dem Schlafen vorbeugen, sind ungewöhnlich, z. B. KILL. In der Dokumentation heißt es außerdem: "Außerdem kann die Suspendierungszeit aufgrund der Planung anderer Aktivitäten im System um einen beliebigen Betrag länger sein als angefordert." das ist typischer.
Markmnl

1
Singnals und Windows ist einfach albern. Unter Windows wartet Python time.sleep () auf einem ConsoleEvent, um Dinge wie Strg-C zu erfassen.
Schlenk

1

Wenn Sie mehr Präzision oder kürzere Schlafzeiten benötigen, sollten Sie Ihre eigenen erstellen:

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()

Verwenden Sie keine Variable, um das Argument sleep () zu übergeben. Sie müssen die Berechnung direkt in sleep () einfügen.


Und die Rückkehr meines Terminals

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 ──────────────────────

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.