GNU/Linux >> Tutoriales Linux >  >> Linux

¿Por qué la impresión en la salida estándar es tan lenta? ¿Se puede acelerar?

¡Gracias por todos los comentarios! Terminé respondiéndolo yo mismo con tu ayuda. Sin embargo, se siente sucio responder tu propia pregunta.

Pregunta 1:¿Por qué la impresión en la salida estándar es lenta?

Respuesta: La impresión en la salida estándar no intrínsecamente lento. Es el terminal con el que trabajas el que es lento. Y prácticamente no tiene nada que ver con el almacenamiento en búfer de E/S en el lado de la aplicación (p. ej.:almacenamiento en búfer de archivos de Python). Ver más abajo.

Pregunta 2:¿Se puede acelerar?

Respuesta: Sí, puede, pero aparentemente no desde el lado del programa (el lado que realiza la 'impresión' en la salida estándar). Para acelerarlo, use un emulador de terminal diferente más rápido.

Explicación...

Probé un programa de terminal "ligero" autodenominado llamado wterm y obtuve significativamente Mejores resultados. A continuación se muestra el resultado de mi script de prueba (en la parte inferior de la pregunta) cuando se ejecuta en wterm a 1920x1200 en el mismo sistema en el que la opción de impresión básica tomó 12 segundos usando gnome-terminal:

-----
timing summary (100k lines each)
-----
print                         : 0.261 s
write to file (+fsync)        : 0.110 s
print with stdout = /dev/null : 0.050 s

¡0.26s es MUCHO mejor que 12s! No sé si wterm es más inteligente acerca de cómo se representa en la pantalla en la línea de lo que estaba sugiriendo (representa la cola 'visible' a una velocidad de cuadro razonable), o si simplemente "hace menos" que gnome-terminal . Sin embargo, a los efectos de mi pregunta, tengo la respuesta. gnome-terminal es lento.

Por lo tanto, si tiene una secuencia de comandos de ejecución prolongada que cree que es lenta y arroja grandes cantidades de texto a la salida estándar... ¡pruebe con una terminal diferente y vea si es mejor!

Tenga en cuenta que saqué casi al azar wterm de los repositorios de ubuntu/debian. Este enlace podría ser el mismo terminal, pero no estoy seguro. No probé ningún otro emulador de terminal.

Actualización:como tenía que rascarme la picazón, probé un montón de otros emuladores de terminal con el mismo script y pantalla completa (1920x1200). Mis estadísticas recopiladas manualmente están aquí:

wterm           0.3s
aterm           0.3s
rxvt            0.3s
mrxvt           0.4s
konsole         0.6s
yakuake         0.7s
lxterminal        7s
xterm             9s
gnome-terminal   12s
xfce4-terminal   12s
vala-terminal    18s
xvt              48s

Los tiempos registrados se recopilan manualmente, pero fueron bastante consistentes. Grabé el mejor (ish) valor. YMMV, obviamente.

Como beneficio adicional, ¡fue un recorrido interesante por algunos de los diversos emuladores de terminal disponibles! Estoy sorprendido de que mi primera prueba 'alternativa' haya resultado ser la mejor del grupo.


Su redirección probablemente no haga nada ya que los programas pueden determinar si su FD de salida apunta a un tty.

Es probable que stdout tenga un búfer de línea cuando apunta a una terminal (lo mismo que el stdout de C comportamiento de transmisión).

Como experimento divertido, intente canalizar la salida a cat .

Probé mi propio experimento divertido y estos son los resultados.

$ python test.py 2>foo
...
$ cat foo
-----
timing summary (100k lines each)
-----
print                         : 6.040 s
write to file                 : 0.122 s
print with stdout = /dev/null : 0.121 s

$ python test.py 2>foo |cat
...
$ cat foo
-----
timing summary (100k lines each)
-----
print                         : 1.024 s
write to file                 : 0.131 s
print with stdout = /dev/null : 0.122 s

¿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 de toda la RAM), y es tan rápido como simplemente tirar a la basura con /dev/null?

Enhorabuena, acaba de descubrir la importancia del almacenamiento en búfer de E/S. :-)

El disco aparece para ser más rápido, porque tiene mucho búfer:todos los write() de Python las llamadas regresan antes de que se escriba algo en el disco físico. (El sistema operativo hace esto más tarde, combinando muchos miles de escrituras individuales en fragmentos grandes y eficientes).

El terminal, por otro lado, hace poco o ningún almacenamiento en búfer:cada print individual / write(line) espera el lleno escribir (es decir, mostrar en el dispositivo de salida) para completar.

Para que la comparación sea justa, debe hacer que la prueba del archivo use el mismo búfer de salida que el terminal, lo que puede hacer modificando su ejemplo a:

fp = file("out.txt", "w", 1)   # line-buffered, like stdout
[...]
for x in range(lineCount):
    fp.write(line)
    os.fsync(fp.fileno())      # wait for the write to actually complete

Ejecuté su prueba de escritura de archivos en mi máquina, y con almacenamiento en búfer, también aquí 0.05s para 100,000 líneas.

Sin embargo, con las modificaciones anteriores para escribir sin búfer, se necesitan 40 segundos para escribir solo 1000 líneas en el disco. Dejé de esperar 100.000 líneas para escribir, pero extrapolando lo anterior, me llevaría más de una hora. .

Eso pone en perspectiva los 11 segundos de la terminal, ¿no?

Entonces, para responder a su pregunta original, escribir en una terminal es increíblemente rápido, considerando todas las cosas, y no hay mucho espacio para hacerlo mucho más rápido (pero las terminales individuales varían en la cantidad de trabajo que hacen; vea el comentario de Russ a esto respuesta).

(Podría agregar más búfer de escritura, como con E/S de disco, pero luego no vería lo que se escribió en su terminal hasta después de que se vacíe el búfer. Es una compensación:interactividad versus eficiencia masiva).


No puedo hablar de los detalles técnicos porque no los conozco, pero esto no me sorprende:el terminal no fue diseñado para imprimir muchos datos como este. De hecho, ¡incluso proporciona un enlace a un montón de cosas de GUI que tiene que hacer cada vez que quiere imprimir algo! Tenga en cuenta que si llama al script con pythonw en cambio, no toma 15 segundos; esto es completamente un problema de GUI. Redirigir stdout a un archivo para evitar esto:

import contextlib, io
@contextlib.contextmanager
def redirect_stdout(stream):
    import sys
    sys.stdout = stream
    yield
    sys.stdout = sys.__stdout__

output = io.StringIO
with redirect_stdout(output):
    ...

Linux
  1. ¿Por qué Rm puede eliminar archivos de solo lectura?

  2. ¿Por qué no puedo dividir un archivo .ape?

  3. ¿Por qué puedo iniciar sesión con contraseñas parciales?

  4. Solo la raíz puede montar, ¿por qué?

  5. Linux, ¿por qué no puedo canalizar el resultado de búsqueda a rm?

Por qué uso rxvt como mi terminal

¿Por qué los archivos no pueden ser manipulados por inode?

¿Por qué no puedo acceder a phpmyadmin de Xampp en localhost? El acceso está prohibido.

¿Por qué no puedo elegir una carpeta compartida de VirtualBox?

¿Por qué no puedo matar este proceso en Linux?

¿Por qué no puedo desplazarme en la terminal?