107 votes

Comment arrêter une boucle while après un certain temps ?

Comment arrêter une boucle while après 5 minutes si elle n'atteint pas ce que je veux qu'elle atteigne.

while true:
    test = 0
    if test == 5:
        break
    test = test - 1

Ce code me jette dans une boucle sans fin.

169voto

Andrew Clark Points 77748

Essayez ce qui suit :

import time
timeout = time.time() + 60*5   # 5 minutes from now
while True:
    test = 0
    if test == 5 or time.time() > timeout:
        break
    test = test - 1

Vous pouvez également ajouter un court sommeil ici pour que cette boucle ne monopolise pas le CPU (par exemple time.sleep(1) au début ou à la fin du corps de la boucle).

59voto

Petr Krampl Points 478

Vous n'avez pas besoin d'utiliser le while True: dans ce cas. Il existe un moyen beaucoup plus simple d'utiliser directement la condition temporelle :

import time

# timeout variable can be omitted, if you use specific value in the while condition
timeout = 300   # [seconds]

timeout_start = time.time()

while time.time() < timeout_start + timeout:
    test = 0
    if test == 5:
        break
    test -= 1

49voto

andrefsp Points 923

Essayez ce module : http://pypi.python.org/pypi/interruptingcow/

from interruptingcow import timeout
try:
    with timeout(60*5, exception=RuntimeError):
        while True:
            test = 0
            if test == 5:
                break
            test = test - 1
except RuntimeError:
    pass

28voto

Anthony Points 1290

La réponse de Petr Krampl est la meilleure à mon avis, mais il faut en dire plus sur la nature des boucles et sur la façon d'optimiser l'utilisation du système. Les débutants qui tombent sur ce fil de discussion risquent d'être encore plus désorientés par les erreurs logiques et algorithmiques de la question et des réponses existantes.

Tout d'abord, regardons ce que fait votre code tel que vous l'avez écrit à l'origine :

while True:
    test = 0
    if test == 5:
        break
    test = test - 1

Si vous dites while True dans un contexte de boucle, normalement votre intention est de rester dans la boucle pour toujours. Si ce n'est pas votre intention, vous devriez envisager d'autres options pour la structure de la boucle. Petr Krampl vous a montré une façon parfaitement raisonnable de gérer ce problème, qui est beaucoup plus claire pour quelqu'un d'autre qui pourrait lire votre code. En outre, elle sera plus claire pour vous plusieurs mois plus tard si vous devez revoir votre code pour ajouter ou corriger quelque chose. Un code bien écrit fait partie de votre documentation. Il existe généralement plusieurs façons de faire les choses, mais cela ne signifie pas que toutes les façons sont également valables dans tous les contextes. while true en est un bon exemple, surtout dans ce contexte.

Ensuite, nous allons examiner l'erreur algorithmique dans votre code original. La toute première chose que vous faites dans la boucle est d'assigner 0 à test . La prochaine étape consiste à vérifier si la valeur de la variable test est 5, ce qui ne sera jamais le cas, sauf si plusieurs threads modifient le même emplacement mémoire. Le threading n'entre pas dans le cadre de cette discussion, mais il est intéressant de noter que le code pourrait techniquement fonctionner, mais même avec plusieurs threads, beaucoup de choses manqueraient, par exemple les sémaphores. De toute façon, vous resterez dans cette boucle pour toujours, même si la sentinelle force une boucle infinie.

La déclaration test = test - 1 est inutile, quelle que soit son action, car la variable est réinitialisée au début de l'itération suivante de la boucle. Même si vous la modifiez pour qu'elle soit test = 5 la boucle serait toujours infinie car la valeur est réinitialisée à chaque fois. Si vous déplacez l'instruction d'initialisation en dehors de la boucle, elle aura au moins une chance de sortir. Ce que vous vouliez peut-être, c'était quelque chose comme ceci :

test = 0
while True:
    test = test - 1
    if test == 5:
        break

L'ordre des instructions dans la boucle dépend de la logique de votre programme. Il fonctionnera cependant dans les deux ordres, ce qui est le point principal.

Le problème suivant est l'erreur logique potentielle et probable de commencer à 0, de soustraire continuellement 1, puis de comparer avec un nombre positif. Oui, il y a des occasions où cela peut être ce que vous avez l'intention de faire tant que vous comprenez les implications, mais ce n'est très probablement pas ce que vous vouliez. Les versions plus récentes de Python ne s'emballent pas lorsque vous atteignez le "bas" de la plage d'un nombre entier, comme le font le C et d'autres langages. Il vous laissera continuer à soustraire 1 jusqu'à ce que vous ayez rempli la mémoire disponible sur votre système ou du moins ce qui est alloué à votre processus. Regardez le script suivant et les résultats :

test = 0

while True:
    test  -= 1

    if test % 100 == 0:
        print "Test = %d" % test

    if test == 5:
        print "Test = 5"
        break

ce qui donne ceci :

Test = -100
Test = -200
Test = -300
Test = -400
...
Test = -21559000
Test = -21559100
Test = -21559200
Test = -21559300
...

La valeur de test ne sera jamais 5, donc cette boucle ne sortira jamais.

Pour compléter la réponse de Petr Krampl, voici une version qui est probablement plus proche de ce que vous vouliez en plus de sortir de la boucle après un certain temps :

import time

test = 0
timeout = 300   # [seconds]

timeout_start = time.time()

while time.time() < timeout_start + timeout:
    if test == 5:
        break
    test -= 1

Il n'y a toujours pas de rupture basée sur la valeur de test mais il s'agit d'une boucle parfaitement valide avec une condition initiale raisonnable. Un contrôle supplémentaire des limites pourrait vous aider à éviter l'exécution d'une très longue boucle sans raison, par exemple en vérifiant si la valeur de test est inférieure à 5 à l'entrée de la boucle, ce qui interromprait immédiatement la boucle.


Il convient de mentionner une autre chose qu'aucune autre réponse n'a abordée. Parfois, lorsque vous effectuez une boucle de ce type, vous ne souhaitez pas consommer le CPU pendant tout le temps imparti. Par exemple, disons que vous vérifiez la valeur d'un élément qui change toutes les secondes. Si vous n'introduisez pas une sorte de délai, vous utiliserez tous les cycles de CPU disponibles alloués à votre processus. C'est bien si c'est nécessaire, mais une bonne conception permettra à de nombreux programmes de fonctionner en parallèle sur votre système sans surcharger les ressources disponibles. Une simple instruction Sleep libérera la grande majorité des cycles CPU alloués à votre processus pour que d'autres programmes puissent travailler.

L'exemple suivant n'est pas très utile, mais il permet de démontrer le concept. Disons que vous voulez imprimer quelque chose toutes les secondes. Une façon de le faire serait la suivante :

import time

tCurrent = time.time()

while True:
    if time.time() >= tCurrent + 1:
        print "Time = %d" % time.time()
        tCurrent = time.time()

Le résultat serait le suivant :

Time = 1498226796
Time = 1498226797
Time = 1498226798
Time = 1498226799

Et l'utilisation de l'unité centrale du processus ressemblerait à ça :

enter image description here

C'est une énorme quantité d'utilisation du CPU pour ne faire pratiquement aucun travail. Ce code est beaucoup plus agréable pour le reste du système :

import time

tCurrent = time.time()

while True:
    time.sleep(0.25) # sleep for 250 milliseconds
    if time.time() >= tCurrent + 1:
        print "Time = %d" % time.time()
        tCurrent = time.time()

Le résultat est le même :

Time = 1498226796
Time = 1498226797
Time = 1498226798
Time = 1498226799

et l'utilisation du CPU est beaucoup, beaucoup plus faible :

enter image description here

7voto

Dpedrinha Points 101
import time

abort_after = 5 * 60
start = time.time()

while True:
  delta = time.time() - start
  if delta >= abort_after:
    break

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X