Siempre me ha sorprendido / frustrado con el tiempo que se tarda simplemente en enviar al terminal una declaración de impresión. Después de un registro reciente dolorosamente lento, decidí investigarlo y me sorprendió bastante descubrir que casi todo el tiempo que pasa está esperando que la terminal procese los resultados.
¿Se puede acelerar de alguna manera la escritura en stdout?
Escribí un script (' print_timer.py
' en la parte inferior de esta pregunta) para comparar el tiempo al escribir 100k líneas en stdout, en un archivo y con stdout redirigido a /dev/null
. Aquí está el resultado del tiempo:
$ 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
Guau. Para asegurarme de que Python no está haciendo algo detrás de escena, como reconocer que reasigné stdout a / dev / null o algo así, realicé la redirección fuera del 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
Entonces no es un truco de Python, es solo la terminal. Siempre supe que volcar la salida a / dev / null aceleró las cosas, ¡pero nunca pensé que fuera tan significativo!
Me sorprende lo lento que es el tty. ¿Cómo puede ser que escribir en el disco físico sea MUCHO más rápido que escribir en la "pantalla" (presumiblemente una operación todo RAM), y es efectivamente tan rápido como simplemente tirar a la basura con / dev / null?
Este enlace habla sobre cómo el terminal bloqueará las E / S para que pueda "analizar [la entrada], actualizar su buffer de trama, comunicarse con el servidor X para desplazar la ventana y así sucesivamente" ... pero no lo hago Lo entiendo completamente. ¿Qué puede llevar tanto tiempo?
Espero que no haya salida (¿menos que una implementación tty más rápida?), Pero creo que preguntaría de todos modos.
ACTUALIZACIÓN: después de leer algunos comentarios, me pregunté cuánto impacto tiene realmente el tamaño de mi pantalla en el tiempo de impresión, y tiene cierta importancia. Los números realmente lentos anteriores están con mi terminal Gnome volado hasta 1920x1200. Si lo reduzco muy pequeño me sale ...
-----
timing summary (100k lines each)
-----
print : 2.920 s
write to file (+fsync) : 0.121 s
print with stdout = /dev/null : 0.048 s
Eso es ciertamente mejor (~ 4x), pero no cambia mi pregunta. Solo se agrega a mi pregunta, ya que no entiendo por qué la representación de la pantalla del terminal debería ralentizar la escritura de una aplicación en stdout. ¿Por qué mi programa necesita esperar a que continúe el procesamiento de pantalla?
¿Todas las aplicaciones de terminal / tty no son iguales? Todavía tengo que experimentar. Realmente me parece que un terminal debería ser capaz de almacenar en búfer todos los datos entrantes, analizarlos / renderizarlos de manera invisible, y solo renderizar el fragmento más reciente que es visible en la configuración de pantalla actual a una velocidad de cuadro razonable. Entonces, si puedo escribir + fsync en el disco en ~ 0.1 segundos, un terminal debería poder completar la misma operación en algo de ese orden (con quizás algunas actualizaciones de pantalla mientras lo hacía).
Todavía espero que haya una configuración tty que se pueda cambiar desde el lado de la aplicación para mejorar este comportamiento para el programador. Si esto es estrictamente un problema de aplicación de terminal, ¿entonces quizás esto ni siquiera pertenece a StackOverflow?
¿Qué me estoy perdiendo?
Aquí está el programa python utilizado para generar el tiempo:
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