web-dev-qa-db-fra.com

Comment pourrais-je arrêter une boucle while après n durée?

comment pourrais-je arrêter une boucle while après 5 minutes si elle n'atteint pas ce que je veux qu'elle réalise.

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

Ce code me jette dans une boucle sans fin.

48
Adilicious

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 voudrez peut-être aussi ajouter un court sommeil ici pour que cette boucle n'emballe pas le processeur (par exemple time.sleep(1) au début ou à la fin du corps de la boucle).

79
Andrew Clark

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

Cordialement

30
andrefsp

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

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
27
Petr Krampl

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 manière d'optimiser l'utilisation du système. Les débutants qui tombent sur ce fil peuvent être encore plus déconcertés par les erreurs logiques et algorithmiques de la question et les réponses existantes.

Premièrement, regardons ce que votre code fait comme 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, votre intention est normalement 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é un moyen parfaitement raisonnable de gérer cela, ce qui est beaucoup plus clair pour quelqu'un qui pourrait lire votre code. En outre, vous aurez plus de clarté 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 y a généralement plusieurs façons de faire les choses, mais cela ne les rend pas toutes également valables dans tous les contextes. while true en est un bon exemple, particulièrement dans ce contexte.

Ensuite, nous examinerons l’erreur algorithmique dans votre code original. La toute première chose que vous faites dans la boucle est d'affecter 0 à test. La prochaine étape consiste à vérifier si la valeur de test est 5, ce qui ne sera jamais le cas à moins que plusieurs threads modifient le même emplacement mémoire. Les discussions ne font pas partie de cette discussion, mais il convient de noter que le code pourrait fonctionner techniquement, mais que même avec plusieurs threads, il en manquerait beaucoup, par exemple. sémaphores. Quoi qu'il en soit, vous resterez dans cette boucle pour toujours, indépendamment du fait que la sentinelle force une boucle infinie.

L'instruction test = test - 1 est inutile quelle que soit sa fonction car la variable est réinitialisée au début de la prochaine itération de la boucle. Même si vous le changiez en 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 souhaitiez peut-être é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. Cela fonctionnera dans l'un ou l'autre ordre, cependant, ce qui est le point principal.

Le prochain problème est l'erreur logique potentielle et probable de commencer à 0, en soustrayant continuellement 1 et en comparant ensuite avec un nombre positif. Oui, il y a des cas où c'est ce que vous avez l'intention de faire tant que vous en comprenez les implications, mais ce n'est probablement pas ce que vous vouliez. Les versions les plus récentes de python ne seront pas complètes lorsque vous atteindrez le "bas" de la plage d'un entier, tel que C, et de nombreux autres langages. Cela vous permettra de continuer à soustraire 1 jusqu'à ce que vous ayez rempli la mémoire disponible sur votre système ou au 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

qui produit 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, cette boucle ne se fermera donc jamais.

Pour ajouter à la réponse de Petr Krampl, voici une version qui est probablement plus proche de ce que vous vouliez réellement 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 ne sera toujours pas cassé basé sur la valeur de test, mais c'est une boucle parfaitement valide avec une condition initiale raisonnable. Une vérification supplémentaire des limites pourrait vous aider à éviter l'exécution d'une très longue boucle sans aucune raison, par exemple. vérifie si la valeur de test est inférieure à 5 à l'entrée de la boucle, ce qui romprait immédiatement la boucle.


Il convient de mentionner une autre chose à laquelle aucune autre réponse n’a été apportée. Parfois, lorsque vous faites une boucle comme celle-ci, vous ne souhaitez peut-être pas utiliser le processeur pendant tout le temps imparti. Par exemple, supposons que vous vérifiez la valeur de quelque chose qui change à chaque seconde. Si vous n'introduisez pas de délai, vous utiliseriez chaque cycle de processeur disponible attribué à votre processus. C'est bien si cela est nécessaire, mais une bonne conception permettra à de nombreux programmes de s'exécuter en parallèle sur votre système sans surcharger les ressources disponibles. Une simple instruction de mise en veille permettra de libérer la grande majorité des cycles de traitement alloués à votre processus afin que d'autres programmes puissent fonctionner.

L'exemple suivant n'est pas très utile, mais il illustre le concept. Disons que vous voulez imprimer quelque chose chaque seconde. 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()

La sortie serait la suivante:

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

Et l'utilisation du processeur de processus ressemblerait à ceci:

 enter image description here

Cela représente une énorme quantité d’utilisation du processeur 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()

La sortie est la même:

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

et l'utilisation du processeur est beaucoup, beaucoup plus bas:

 enter image description here

6
Anthony
import time

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

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

Je veux partager celui que j'utilise:

import time
# provide a waiting-time list:
lst = [1,2,7,4,5,6,4,3]
# set the timeout limit
timeLimit = 4

for i in lst:
    timeCheck = time.time()
    while True:
        time.sleep(i)
        if time.time() <= timeCheck + timeLimit:
            print ([i,'looks ok'])
            break
        else:
            print ([i,'too long'])
            break

Ensuite, vous obtiendrez:

[1, 'looks ok']
[2, 'looks ok']
[7, 'too long']
[4, 'looks ok']
[5, 'too long']
[6, 'too long']
[4, 'looks ok']
[3, 'looks ok']
0
kennyut