Sono sempre stato sorpreso / frustrato da quanto tempo impieghi semplicemente per inviare al terminale una dichiarazione stampata. Dopo alcune recenti registrazioni dolorosamente lente ho deciso di esaminarlo e sono rimasto piuttosto sorpreso di scoprire che quasi tutto il tempo trascorso è in attesa che il terminale elabori i risultati.
La scrittura su stdout può essere accelerata in qualche modo?
Ho scritto uno script (' print_timer.py
' in fondo a questa domanda) per confrontare i tempi quando si scrivono 100k righe su stdout, su file e con reindirizzamento su stdout /dev/null
. Ecco il risultato della tempistica:
$ python print_timer.py
this is a test
this is a test
<snipped 99997 lines>
this is a test
-----
timing summary (100k lines each)
-----
print :11.950 s
write to file (+ fsync) : 0.122 s
print with stdout = /dev/null : 0.050 s
Wow. Per essere sicuro che Python non stia facendo qualcosa dietro le quinte come riconoscere che ho riassegnato stdout a / dev / null o qualcosa del genere, ho fatto il reindirizzamento fuori dallo script ...
$ python print_timer.py > /dev/null
-----
timing summary (100k lines each)
-----
print : 0.053 s
write to file (+fsync) : 0.108 s
print with stdout = /dev/null : 0.045 s
Quindi non è un trucco pitone, è solo il terminale. Ho sempre saputo scaricare l'output su / dev / null velocizzando le cose, ma non ho mai pensato che fosse così significativo!
Mi stupisce di quanto sia lento il tty. Come può essere che la scrittura su disco fisico sia VELOCEMENTE più veloce della scrittura sullo "schermo" (presumibilmente una operazione tutta RAM), ed è efficace quanto il semplice scaricamento nella spazzatura con / dev / null?
Questo link parla di come il terminale bloccherà l'I / O in modo che possa "analizzare [l'input], aggiornare il suo frame buffer, comunicare con il server X per scorrere la finestra e così via" ... ma io no ottenerlo completamente. Cosa può richiedere così tanto tempo?
Mi aspetto che non ci sia via d'uscita (a meno di un'implementazione tty più veloce?) Ma immagino che lo chiederei comunque.
AGGIORNAMENTO: dopo aver letto alcuni commenti, mi chiedevo quanto impatto la mia dimensione dello schermo ha effettivamente sul tempo di stampa, e ha un certo significato. I numeri molto lenti sopra sono con il mio terminale Gnome fatto saltare in aria a 1920x1200. Se lo riduco molto piccolo ottengo ...
-----
timing summary (100k lines each)
-----
print : 2.920 s
write to file (+fsync) : 0.121 s
print with stdout = /dev/null : 0.048 s
È sicuramente meglio (~ 4x), ma non cambia la mia domanda. Aggiunge solo alla mia domanda poiché non capisco perché il rendering dello schermo del terminale dovrebbe rallentare un'applicazione che scrive su stdout. Perché il mio programma deve attendere che il rendering dello schermo continui?
Tutte le app terminal / tty non sono state create uguali? Devo ancora sperimentare. Mi sembra davvero che un terminale dovrebbe essere in grado di bufferizzare tutti i dati in arrivo, analizzarli / renderli in modo invisibile e renderizzare solo il blocco più recente che è visibile nella configurazione dello schermo corrente a un frame rate ragionevole. Quindi, se riesco a scrivere + fsync sul disco in ~ 0,1 secondi, un terminale dovrebbe essere in grado di completare la stessa operazione in qualcosa di quell'ordine (con forse alcuni aggiornamenti dello schermo mentre lo faceva).
Spero ancora che ci sia un'impostazione tty che può essere modificata dal lato dell'applicazione per rendere questo comportamento migliore per il programmatore. Se questo è strettamente un problema con l'applicazione terminale, forse questo non appartiene nemmeno a StackOverflow?
Cosa mi sto perdendo?
Ecco il programma Python utilizzato per generare i tempi:
import time, sys, tty
import os
lineCount = 100000
line = "this is a test"
summary = ""
cmd = "print"
startTime_s = time.time()
for x in range(lineCount):
print line
t = time.time() - startTime_s
summary += "%-30s:%6.3f s\n" % (cmd, t)
#Add a newline to match line outputs above...
line += "\n"
cmd = "write to file (+fsync)"
fp = file("out.txt", "w")
startTime_s = time.time()
for x in range(lineCount):
fp.write(line)
os.fsync(fp.fileno())
t = time.time() - startTime_s
summary += "%-30s:%6.3f s\n" % (cmd, t)
cmd = "print with stdout = /dev/null"
sys.stdout = file(os.devnull, "w")
startTime_s = time.time()
for x in range(lineCount):
fp.write(line)
t = time.time() - startTime_s
summary += "%-30s:%6.3f s\n" % (cmd, t)
print >> sys.stderr, "-----"
print >> sys.stderr, "timing summary (100k lines each)"
print >> sys.stderr, "-----"
print >> sys.stderr, summary