Quelle est la précision de time.sleep () de Python?

95

Je peux lui donner des nombres à virgule flottante, tels que

time.sleep(0.5)

mais quelle est sa précision? Si je le donne

time.sleep(0.05)

va-t-il vraiment dormir environ 50 ms?

Claudiu
la source

Réponses:

78

La précision de la fonction time.sleep dépend de la précision du sommeil de votre système d'exploitation sous-jacent. Pour les systèmes d'exploitation qui ne sont pas en temps réel, comme un Windows standard, le plus petit intervalle de sommeil pendant lequel vous pouvez dormir est d'environ 10 à 13 ms. J'ai vu des sommeil précis en quelques millisecondes après ce moment au-dessus des 10-13 ms minimum.

Mise à jour: comme mentionné dans les documents cités ci-dessous, il est courant de faire le sommeil en boucle qui s'assurera de se rendormir si cela vous réveille tôt.

Je dois également mentionner que si vous utilisez Ubuntu, vous pouvez essayer un pseudo noyau en temps réel (avec le jeu de correctifs RT_PREEMPT) en installant le package du noyau rt (au moins dans Ubuntu 10.04 LTS).

EDIT: Correction des noyaux Linux non temps réel ont un intervalle de sommeil minimum beaucoup plus proche de 1 ms puis de 10 ms mais cela varie de manière non déterministe.

Joseph Lisee
la source
8
En fait, les noyaux Linux ont par défaut un taux de ticks plus élevé pendant un certain temps, donc le sommeil "minimum" est beaucoup plus proche de 1 ms que de 10 ms. Ce n'est pas garanti - une autre activité du système peut empêcher le noyau de planifier votre processus dès que vous le souhaitez, même sans conflit de processeur. C'est ce que les noyaux en temps réel essaient de corriger, je pense. Mais, à moins que vous n'ayez vraiment besoin d'un comportement en temps réel, le simple fait d'utiliser un taux de ticks élevé (paramètre HZ du noyau) vous permettra de dormir sans garantie, mais à haute résolution sous Linux sans utiliser quoi que ce soit de spécial.
Glenn Maynard
1
Oui, vous avez raison, j'ai essayé avec Linux 2.6.24-24 et j'ai pu obtenir des taux de mise à jour assez proches de 1000 Hz. Au moment où je faisais cela, j'exécutais également le code sur Mac et Windows, donc j'étais probablement confus. Je sais que Windows XP a au moins un taux de tick d'environ 10 ms.
Joseph Lisee
Sous Windows 8, je reçois un peu moins de 2 ms
markmnl
2
De plus, la précision ne dépend pas seulement du système d'exploitation, mais de ce que le système d'exploitation fait à la fois sur Windows et Linux s'ils sont occupés à faire quelque chose de plus important sleep()dans la documentation "le temps de suspension peut être plus long que demandé par une quantité arbitraire en raison de la planification de autre activité du système ".
markmnl
55

Les gens ont tout à fait raison sur les différences entre les systèmes d'exploitation et les noyaux, mais je ne vois aucune granularité dans Ubuntu et je vois une granularité de 1 ms dans MS7. Suggérant une implémentation différente de time.sleep, pas seulement un taux de tick différent. Une inspection plus approfondie suggère une granularité de 1 μs dans Ubuntu, mais cela est dû à la fonction time.time que j'utilise pour mesurer la précision. Comportement time.sleep typique de Linux et Windows en Python

Wilbert
la source
6
Il est intéressant de voir comment Linux a choisi de toujours dormir un peu plus longtemps que demandé, alors que Microsoft a choisi l'approche opposée.
jleahy
2
@jleahy - l'approche linux a du sens pour moi: le sommeil est vraiment une libération de la priorité d'exécution pendant un laps de temps après lequel vous vous soumettez à nouveau à la volonté du planificateur (qui peut ou non vous planifier l'exécution tout de suite) .
underrun
2
comment avez-vous obtenu les résultats? Pourriez-vous fournir le code source? Le graphique ressemble à un artefact de l'utilisation de différents minuteries pour mesurer le temps et le sommeil (en principe, vous pouvez même utiliser la dérive entre les minuteries comme source d'aléatoire ).
jfs
1
@JF Sebastian - La fonction que j'ai utilisée se trouve dans socsci.ru.nl/wilberth/computer/sleepAccuracy.html . Le troisième graphique montre un effet similaire à ce que vous voyez, mais de seulement 1 ‰.
Wilbert
1
@JF Sebastian J'utilise time.clock () sur Windows
Wilbert
26

De la documentation :

D'autre part, la précision de time()et sleep()est meilleure que leurs équivalents Unix: les temps sont exprimés en nombres à virgule flottante, time()renvoie le temps le plus précis disponible (en utilisant Unix gettimeofday si disponible), et sleep()acceptera un temps avec une fraction non nulle (Unix selectest utilisé pour l'implémenter, le cas échéant).

Et plus précisément par rapport'a sleep():

Suspendez l'exécution pendant le nombre de secondes donné. L'argument peut être un nombre à virgule flottante pour indiquer un temps de sommeil plus précis. Le temps de suspension réel peut être inférieur à celui demandé car tout signal capturé mettra fin à l' sleep()exécution suivante de la routine de capture de ce signal. En outre, le temps de suspension peut être plus long que demandé par une quantité arbitraire en raison de la programmation d'autres activités dans le système.

Stephan202
la source
1
Quelqu'un peut-il expliquer le "parce que tout signal capturé mettra fin à sleep () après l'exécution de la routine de capture de ce signal"? De quels signaux fait-il référence? Merci!
Diego Herranz
1
Les signaux sont comme les notifications gérées par le système d'exploitation ( en.wikipedia.org/wiki/Unix_signal ), cela signifie que si le système d'exploitation a capté un signal, sleep () est terminé après avoir traité ce signal.
ArianJM
23

Voici ma suite à la réponse de Wilbert: la même chose pour Mac OS X Yosemite, car elle n'a pas encore été beaucoup mentionnée.Comportement de veille de Mac OS X Yosemite

On dirait que la plupart du temps, il dort environ 1,25 fois le temps que vous demandez et parfois entre 1 et 1,25 fois le temps que vous demandez. Il ne dort presque jamais (~ deux fois sur 1000 échantillons) de manière significative plus de 1,25 fois le temps que vous demandez.

De plus (non montré explicitement) la relation 1.25 semble assez bien tenir jusqu'à ce que vous tombiez en dessous d'environ 0,2 ms, après quoi elle commence à devenir un peu floue. De plus, le temps réel semble s'établir à environ 5 ms de plus que ce que vous demandez après que le temps demandé dépasse 20 ms.

Encore une fois, il semble être une implémentation complètement différente de sleep()sous OS X que sous Windows ou quel que soit le noyau Linux que Wilbert utilisait.

Tim Supinie
la source
Pourriez-vous télécharger le code source du benchmark sur github / bitbucket?
jfs
3
Je l' ai essayé il sur ma machine. Le résultat est similaire à la réponse de @ Wilbert .
jfs
Je suppose que le sommeil lui-même est précis, mais la planification de Mac OS X n'est pas assez précise pour fournir un processeur suffisamment rapide pour que le réveil du sommeil soit retardé. Si une heure de réveil précise est importante, il semble que le sommeil devrait être réglé à 0,75 fois le temps réellement demandé et vérifier l'heure après le réveil et dormir à plusieurs reprises pendant de moins en moins jusqu'à l'heure correcte.
Mikko Rantalainen
16

Pourquoi ne le découvrez-vous pas:

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

Pour mémoire, j'obtiens une erreur d'environ 0,1 ms sur mon HTPC et 2 ms sur mon ordinateur portable, les deux machines Linux.

Fourmis Aasma
la source
10
Les tests empiriques vous donneront une vue très étroite. Il existe de nombreux noyaux, systèmes d'exploitation et configurations de noyau qui affectent cela. Les noyaux Linux plus anciens utilisent par défaut un taux de ticks inférieur, ce qui se traduit par une plus grande granularité. Dans l'implémentation Unix, un signal externe pendant la mise en veille l'annulera à tout moment, et d'autres implémentations pourraient avoir des interruptions similaires.
Glenn Maynard
6
Bien entendu, l'observation empirique n'est pas transférable. Outre les systèmes d'exploitation et les noyaux, de nombreux problèmes transitoires affectent cela. Si des garanties strictes en temps réel sont nécessaires, alors la conception du système dans son ensemble, depuis le matériel, doit être prise en considération. Je viens de trouver les résultats pertinents compte tenu des affirmations selon lesquelles 10 ms est la précision minimale. Je ne suis pas chez moi dans le monde Windows, mais la plupart des distributions Linux exécutent des noyaux sans tiques depuis un certain temps maintenant. Avec le multicœur désormais répandu, il est fort probable que la planification soit très proche du délai d'expiration.
Ants Aasma
4

Petite correction, plusieurs personnes mentionnent que le sommeil peut être interrompu prématurément par un signal. Dans les documents 3.6, il est dit,

Modifié dans la version 3.5: La fonction dort maintenant au moins secondes même si le sommeil est interrompu par un signal, sauf si le gestionnaire de signal lève une exception (voir PEP 475 pour la justification).

utilisateur405
la source
3

Vous ne pouvez pas vraiment garantir quoi que ce soit à propos du sommeil (), sauf qu'il fera au moins un meilleur effort pour dormir tant que vous le lui avez dit (les signaux peuvent tuer votre sommeil avant la fin du temps, et bien d'autres choses peuvent le faire fonctionner. longue).

Certes, le minimum que vous pouvez obtenir sur un système d'exploitation de bureau standard sera d'environ 16 ms (granularité de la minuterie plus temps de changement de contexte), mais il y a de fortes chances que l'écart en% par rapport à l'argument fourni soit significatif lorsque vous essayez. dormir pendant 10s de millisecondes.

Les signaux, les autres threads contenant le GIL, le plaisir de la planification du noyau, le pas à pas de la vitesse du processeur, etc. peuvent tous faire des ravages avec la durée de sommeil de votre thread / processus.

Nick Bastin
la source
3
La documentation dit le contraire:> Le temps de suspension réel peut être inférieur à celui demandé car tout signal capturé mettra fin à sleep () après l'exécution de la routine de capture de ce signal.
Glenn Maynard
Ah bon, j'ai corrigé le poste, bien que dormir plus longtemps () soit beaucoup plus probable que des plus courts.
Nick Bastin
1
Deux ans et demi plus tard ... la documentation est toujours là. Sous Windows, les signaux ne mettront pas fin au mode veille (). Testé sur Python 3.2, WinXP SP3.
Dave
Oui, mais les signaux empêchant le sommeil sont inhabituels, par exemple KILL, la documentation dit également: "De plus, le temps de suspension peut être plus long que demandé par une quantité arbitraire en raison de la planification d'autres activités dans le système." ce qui est plus typique.
markmnl
1
Singnals and Windows est tout simplement idiot. Sous Windows, time.sleep () Python attend sur un ConsoleEvent pour capturer des éléments tels que Ctrl-C.
schlenk
1

si vous avez besoin de plus de précision ou de temps de sommeil plus courts, pensez à créer le vôtre:

import time

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

J'ai testé cela récemment sur Python 3.7 sous Windows 10. La précision était d'environ 1 ms.

Aleksandar Kiridžić
la source
3
Comment l'avez-vous testé?
Agustin Barrachina
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()

N'utilisez pas de variable pour passer l'argument de sleep (), vous devez insérer le calcul directement dans sleep ()


Et le retour de mon terminal

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

forrest
la source