2010-06-23 17 views
9

¿Por qué tarda tanto en imprimir una nueva línea? ¿Es esto solo mi máquina, o otros ven el mismo efecto?¿Por qué tarda tanto en imprimir " n" en Perl?

Con la nueva línea:

#!/usr/bin/perl 

use strict; 
use Benchmark; 

    timethis(100000,'main();'); 


    sub main { 
     print "you are the bomb. \n"; 
    } 


    # outputs: 
    # timethis 100000: 8 wallclock secs (0.15 usr + 0.45 sys = 0.60 CPU) @ 166666.67/s (n=100000) 

W/o el salto de línea:

#!/usr/bin/perl 

use strict; 
use Benchmark; 

    timethis(100000,'main();'); 


    sub main { 
     print "you are the bomb. "; 
    } 


    # outputs: 
    # timethis 100000: 0 wallclock secs (0.09 usr + 0.04 sys = 0.13 CPU) @ 769230.77/s (n=100000) 
    #  (warning: too few iterations for a reliable count) 

Editar: me gustaría añadir que la colocación de dos "\ n" hace que la ejecución para tomar el doble de tiempo, al menos para los segundos de wallclock.

timethis 100000: 16 wallclock secs (0.15 usr + 0.52 sys = 0.67 CPU) @ 149253.73/s (n=100000) 
+0

¿se está ejecutando en Windows? ¿Puedes probar el mismo código en linux o mac? En mi experiencia, escribir en la consola en Windows es un procedimiento dolorosamente lento, mientras que en los otros 2 de los Tres Grandes es muy, muy rápido. – rmeador

+0

@rmeador: me estoy ejecutando en Linux. Podré hacer más pruebas un poco más tarde. No sabía si esto era habitual para líneas nuevas, o si era b/c de la configuración (sistema operativo, terminal, Perl, hardware, etc.). – vol7ron

+0

como han dicho las respuestas, la nueva línea siempre es lenta, me preguntaba si estaba viendo una desaceleración completamente inesperada debido a que Windows tiene soporte de consola extraño. – rmeador

Respuesta

12

no creo búfer tiene mucho que ver con ello. Supongo que es porque la terminal necesita desplazarse cuando imprime una nueva línea (o imprime suficientes caracteres para llenar una línea). Cuando comparo estas funciones escribiendo en un archivo o en /dev/null, no hay mucha diferencia.

use Benchmark; 
timethis(1000000, 'main'); 
timethis(1000000, 'main2'); 
select STDERR; $| = 0; select STDOUT; # enable buffering on STDERR 
sub main { print STDERR "you are the bomb. \n" } 
sub main2 { print STDERR "you are the bomb. " } 

$ perl benchmark.pl 2> a_file 
timethis 1000000: 21 wallclock secs (4.67 usr + 13.38 sys = 18.05 CPU) @ 55410.87/s 
timethis 1000000: 21 wallclock secs (4.91 usr + 13.34 sys = 18.25 CPU) @ 54797.52/s 

$ perl benchmark.pl 2> /dev/null 
timethis 1000000: 26 wallclock secs (2.86 usr + 10.36 sys = 13.22 CPU) @ 75648.69/s 
timethis 1000000: 27 wallclock secs (2.86 usr + 10.30 sys = 13.16 CPU) @ 76010.95/s 

$ perl benchmark.pl 2> a_file  (without buffering) 
timethis 1000000: 29 wallclock secs (3.78 usr + 12.14 sys = 15.92 CPU) @ 62806.18/s 
timethis 1000000: 29 wallclock secs (3.27 usr + 12.51 sys = 15.78 CPU) @ 63367.34/s 

$ perl benchmark.pl 2> /dev/tty (window has 35 lines and buffers 10000, YMMV) 
[ 200000 declarations of how you are a bomb deleted ] 
timethis 100000: 53 wallclock secs (0.98 usr + 3.73 sys = 4.72 CPU) @ 21190.93/s 
timethis 100000: 9 wallclock secs (0.36 usr + 1.94 sys = 2.30 CPU) @ 43535.05/s 

Resumen: el enjuague adicional reduce el rendimiento en aproximadamente un 10%. El desplazamiento adicional en el terminal reduce el rendimiento en aproximadamente un 50%.

+0

¿Significa eso que cualquier escritura de un idioma en la consola tendría un rendimiento similar? – justkt

+0

Creo que esta podría ser la respuesta correcta. Como se muestra al comparar mi edición con el primer ejemplo (dos nuevas líneas contra una), aparte de los segundos de reloj de pared, que es el tiempo real, los segundos de la CPU son casi los mismos. Creo que la diferencia solo se puede deducir a una operación de terminal, que solo podría suponer que sería causada por el desplazamiento, o reposicionando el cursor desde una nueva línea. – vol7ron

+0

@justkt, eso sería una gran adición al punto de referencia. ¿Podrías intentarlo? :) – vol7ron

3

nueva línea flushes output.

En la mayoría de las implementaciones stdio, buffering varía con el tipo de dispositivo de salida ... dispositivos en serie, incluyendo terminales de, módems, ratones y joysticks, son normalmente tamponada de línea; stdio envía toda la línea a cabo sólo cuando se pone la nueva línea

+0

La salida es a la terminal y se ve ya sea como: "que son la bomba que son la bomba ... que son la bomba Timethis 100000..: Seg # wallclock ..." o "usted es la bomba. Usted es la bomba. ... usted es la bomba. Timethis 100000: # wallclock segundos ..." Por lo tanto, todos los resultados se muestran antes de los datos de referencia. ¿El enjuague todavía tiene un efecto sobre esto? Solo he notado problemas con la descarga, como dice el ejemplo, generalmente en scripts cgi. editar: este comentario no mantiene el formato, el 1er ejemplo enumera la salida con la nueva línea, la 2da imprime consecutivamente. – vol7ron

+0

Gracias por la adición, pero también dice: "La función de impresión de Perl no admite una salida realmente sin búfer, una escritura física para cada carácter individual. En cambio, admite el almacenamiento en búfer de comandos, en el que se realiza una escritura física después de cada comando de salida. " - Esperaría que cada ejecución de impresión sea de salida recta, sin necesidad de memoria intermedia. – vol7ron

8

No es la \n per se lo que causa este problema. Por el contrario, las llamadas sucesivas a print son almacenadas en el SO hasta que se encuentre el carácter \n o el buffer esté lleno. En ese punto, el buffer de salida se vacía a la pantalla. Limpiar la salida de la pantalla es una operación (relativamente) costosa, por lo que el bucle en el que vaciar el búfer de salida muchas veces tiene un rendimiento mucho más lento que el bucle en el que solo vacía el búfer una vez al final (lo que ocurre implícitamente cuando salidas del programa).

+1

También intenté activar el autoflush: "$ | ++;" en la segunda línea Esto no pareció tener ningún efecto. – vol7ron

Cuestiones relacionadas