risposta di
Petr Krampl è il migliore a mio parere, ma c'è ancora molto da dire circa la natura del loop e come ottimizzare l'utilizzo del sistema . I principianti che si trovano su questo thread possono essere ulteriormente confusi dagli errori logici e algoritmici nella domanda e dalle risposte esistenti.
In primo luogo, diamo un'occhiata a ciò che il codice fa, come è stato originariamente scritto che:
while True:
test = 0
if test == 5:
break
test = test - 1
Se si dice while True
in un contesto ciclo, di solito la vostra intenzione è di rimanere nel ciclo per sempre. Se questa non è la tua intenzione, dovresti prendere in considerazione altre opzioni per la struttura del ciclo. Petr Krampl ti ha mostrato un modo perfettamente ragionevole per gestirlo, che è molto più chiaro a qualcun altro che potrebbe leggere il tuo codice. Inoltre, ti sarà più chiaro qualche mese più tardi nel caso in cui avessi bisogno di rivisitare il tuo codice per aggiungere o correggere qualcosa. Il codice ben scritto fa parte della tua documentazione. Di solito ci sono diversi modi di fare le cose, ma questo non rende tutti i metodi ugualmente validi in tutti i contesti. while true
è un buon esempio di questo specialmente in questo contesto.
Successivamente, esamineremo l'errore algoritmico nel codice originale. La prima cosa che fai nel loop è assegnare da 0 a test
. La prossima cosa che fai è verificare se il valore di test
è 5, il che non sarà mai il caso, a meno che tu non abbia più thread che modificano la stessa posizione di memoria. Il threading non rientra nell'ambito di questa discussione, ma vale la pena notare che il codice potrebbe funzionare tecnicamente, ma anche con più thread mancherebbe molto, ad es. semafori. Ad ogni modo, ti troverai in questo ciclo per sempre a prescindere dal fatto che la sentinella stia forzando un ciclo infinito.
La dichiarazione test = test - 1
è inutile indipendentemente da ciò che fa perché la variabile viene reimpostata all'inizio della successiva iterazione del ciclo. Anche se lo hai modificato in test = 5
, il ciclo sarebbe ancora infinito perché il valore viene reimpostato ogni volta. Se sposti l'istruzione di inizializzazione al di fuori del ciclo, allora avrà almeno la possibilità di uscire. Quello che si può avere inteso era qualcosa di simile:
test = 0
while True:
test = test - 1
if test == 5:
break
L'ordine delle istruzioni del ciclo dipende dalla logica del programma.Funzionerà in qualsiasi ordine, però, che è il punto principale.
Il prossimo numero è il probabile e probabile errore logico di iniziare da 0, sottraendo continuamente 1 e quindi confrontandolo con un numero positivo. Sì, ci sono occasioni in cui questo potrebbe effettivamente essere ciò che intendi fare purché tu capisca le implicazioni, ma questo probabilmente non è ciò che intendevi. Le versioni più recenti di python non si avvolgeranno quando si raggiunge il "fondo" dell'intervallo di un intero come C e vari altri linguaggi. Ti consentirà di continuare a sottrarre 1 finché non avrai riempito la memoria disponibile sul tuo sistema o almeno ciò che è stato assegnato al tuo processo. Guarda il seguente script ed i risultati:
test = 0
while True:
test -= 1
if test % 100 == 0:
print "Test = %d" % test
if test == 5:
print "Test = 5"
break
che produce questo:
Test = -100
Test = -200
Test = -300
Test = -400
...
Test = -21559000
Test = -21559100
Test = -21559200
Test = -21559300
...
Il valore di test
non sarà mai 5, in modo da questo ciclo non sarà mai uscita.
Per aggiungere alla risposta di Petr Krampl, Ecco una versione che è probabilmente più vicino a quello che effettivamente inteso in aggiunta a uscire dal ciclo dopo un certo periodo di tempo:
import time
test = 0
timeout = 300 # [seconds]
timeout_start = time.time()
while time.time() < timeout_start + timeout:
if test == 5:
break
test -= 1
E ancora non si rompe sulla base di il valore di test
, ma questo è un ciclo perfettamente valido con una condizione iniziale ragionevole. Un ulteriore controllo dei limiti potrebbe aiutarti a evitare l'esecuzione di un ciclo molto lungo senza motivo, ad es. controlla se il valore del test è inferiore a 5 all'entrata del ciclo, il che interromperebbe immediatamente il ciclo.
Un'altra cosa da dire che nessun'altra risposta è stata presa in considerazione. A volte quando si esegue un loop in questo modo, è possibile che non si desideri consumare la CPU per tutto il tempo assegnato. Ad esempio, supponi di controllare il valore di qualcosa che cambia ogni secondo. Se non si introduce una sorta di ritardo, si utilizzerà ogni ciclo disponibile della CPU assegnato al processo. Va bene se è necessario, ma un buon design permetterà a molti programmi di funzionare in parallelo sul tuo sistema senza sovraccaricare le risorse disponibili. Una semplice istruzione del sonno libererà la maggior parte dei cicli della CPU assegnati al processo in modo che altri programmi possano funzionare.
L'esempio seguente non è molto utile, ma dimostra il concetto. Diciamo che vuoi stampare qualcosa ogni secondo. Un modo per farlo sarebbe come questo:
import time
tCurrent = time.time()
while True:
if time.time() >= tCurrent + 1:
print "Time = %d" % time.time()
tCurrent = time.time()
L'uscita sarebbe questo:
Time = 1498226796
Time = 1498226797
Time = 1498226798
Time = 1498226799
E l'utilizzo della CPU processo sarebbe simile a questa:
Ecco una quantità enorme di utilizzo della CPU per fare praticamente nessun lavoro.Questo codice è più comodo il resto del sistema:
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()
L'uscita è la stessa:
Time = 1498226796
Time = 1498226797
Time = 1498226798
Time = 1498226799
e l'utilizzo della CPU è molto, molto inferiore:
Grazie questo funziona :) – Adilicious
Io uso 'timeit.default_timer', che è sempre l'orologio più preciso per la piattaforma. In particolare, 'time.time' ha una granularità di 1/60 s su Windows, che potrebbe non essere sufficiente se si ha un timeout molto breve. Su Python 3, ci sono anche 'time.monotonic',' time.perf_counter' e 'time.process_time', che potrebbero essere migliori (non ho affrontato nessuno di questi molto). – jpkotta
Ci sono troppe condizioni da elaborare in questa soluzione. Questo dovrebbe essere ottimizzato e 'while True' sostituito con' while time.time()