¿Cuál es la forma más rápida de ejecutar un script?

22

Me preguntaba cuál es la forma más rápida de ejecutar un script, he estado leyendo que hay una diferencia de velocidad entre mostrar el resultado del script en el terminal, redirigirlo a un archivo o tal vez /dev/null.

Entonces, si el resultado no es importante, ¿cuál es la forma más rápida de hacer que el script funcione más rápido, incluso si es mínimo?

bash ./myscript.sh 
-or-
bash ./myscript.sh > myfile.log
-or-
bash ./myscript.sh > /dev/null
Kingofkech
fuente
Comparar "redirigir a un archivo normal" y "redirigir a / dev / null" me parece muy extraño ...
el.pescado

Respuestas:

31

Los terminales en estos días son más lentos de lo que solían ser, principalmente porque las tarjetas gráficas ya no se preocupan por la aceleración 2D. De hecho, imprimir en un terminal puede ralentizar un script, particularmente cuando se trata de desplazarse.

En consecuencia, ./script.shes más lento que ./script.sh >script.log, lo que a su vez es más lento que /script.sh >/dev/null, porque estos últimos implican menos trabajo. Sin embargo, si esto hace una diferencia suficiente para cualquier propósito práctico depende de la cantidad de salida que produce su script y qué tan rápido. Si su script escribe 3 líneas y sale, o si imprime 3 páginas cada pocas horas, probablemente no necesite molestarse con las redirecciones.

Editar: Algunos puntos de referencia rápidos (y completamente rotos):

  • En una consola Linux, 240x75:

    $ time (for i in {1..100000}; do echo $i 01234567890123456789012345678901234567890123456789; done)
    real    3m52.053s
    user    0m0.617s
    sys     3m51.442s
    
  • En un xterm, 260x78:

    $ time (for i in {1..100000}; do echo $i 01234567890123456789012345678901234567890123456789; done)
    real    0m1.367s
    user    0m0.507s
    sys     0m0.104s
    
  • Redireccionar a un archivo, en un disco Samsung SSD 850 PRO 512GB:

     $ time (for i in {1..100000}; do echo $i 01234567890123456789012345678901234567890123456789; done >file)
     real    0m0.532s
     user    0m0.464s
     sys     0m0.068s
    
  • Redirigir a /dev/null:

     $ time (for i in {1..100000}; do echo $i 01234567890123456789012345678901234567890123456789; done >/dev/null)
     real    0m0.448s
     user    0m0.432s
     sys     0m0.016s
    
Satō Katsura
fuente
66
@ Kingofkech eso es menos de 200 líneas / segundo. No haría mucha diferencia. (En comparación, timeout 1 yes "This is a looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong line"imprime más de 100000 líneas en un solo segundo en mi MBP)
Muru
44
@Kingofkech Si se trata de un script, edite un archivo y comente la línea que imprime resultados innecesarios.
Ganará
2
Para una interpretación limitada de "solía ser". Un terminal vt220 es mucho más lento que los emuladores de terminal actuales. Además, las estaciones de trabajo SUN Sparc (las que usé) tenían una consola realmente lenta, por lo que solo redirigir la salida a un archivo al compilar un proyecto más grande aceleraría enormemente el tiempo de compilación.
Kusalananda
1
@Kusalananda Es cierto, xterms en HP Apollo de hace 30 años solía gatear en comparación con xtermsHP-UX de hace 20 años. Sin embargo, una consola Linux con una tarjeta de video Matrox de hace 15 años era más lenta que la misma consola Linux con una tarjeta S3 de hace 20 años. Y una consola Linux con buffer de cuadros de alta resolución en una tarjeta moderna es simplemente inutilizable. :)
Satō Katsura
66
@ Kingofkech Eso es alrededor de 2400 bps. Algunos de nosotros vivimos durante años con esas velocidades. :)
Satō Katsura
14

Hubiera aceptado instintivamente la respuesta de Satō Katsura; que tiene sentido. Sin embargo, es bastante fácil de probar.

Probé escribir un millón de líneas en la pantalla, escribir (agregar) a un archivo y redirigir a /dev/null. Probé cada uno de estos por turno, luego hice cinco réplicas. Estos son los comandos que usé.

$ time (for i in {1..1000000}; do echo foo; done)
$ time (for i in {1..1000000}; do echo foo; done > /tmp/file.log) 
$ time (for i in {1..1000000}; do echo foo; done > /dev/null)

Luego tracé el total de veces a continuación.

trama de tiempo vs. salida

Como puede ver, las presunciones de Satō Katsura eran correctas. Según la respuesta de Satō Katsura, también dudo que el factor limitante sea la salida, por lo que es poco probable que la elección de la salida tenga un efecto sustancial en la velocidad general del guión.

FWIW, mi respuesta original tenía un código diferente, que tenía el archivo anexado y /dev/nullredirigido dentro del bucle.

$ rm /tmp/file.log; touch /tmp/file.log; time (for i in {1..1000000}; do echo foo >> /tmp/file.log; done) 
$ time (for i in {1..1000000}; do echo foo > /dev/null; done)

Como John Kugelman señala en los comentarios, esto agrega muchos gastos generales. Dado que la cuestión está, esto no es realmente el camino correcto para probarlo, pero lo dejaré aquí, ya que muestra claramente el costo de volver a abrir un archivo repetidamente desde dentro de la propia secuencia de comandos.

trama de tiempo vs. salida

En este caso, los resultados se invierten.

Gavilán
fuente
FWIW Agregué un punto de referencia rápido a mi respuesta. En particular, la consola de Linux es> 200 veces más lenta que una xterm, que a su vez es ~ 3 veces más lenta que /dev/null.
Satō Katsura
También debe probar con alguna limitación de velocidad. La salida de OP es de aproximadamente 200 líneas / s.
muru
@muru ¿Quieres decir imprimir una línea, esperar 1/200 segundos y luego repetir? Puedo intentarlo, pero creo que serán resultados similares, pero la señal tardará mucho más en superar el ruido. Aunque tal vez pueda restar el tiempo de espera antes del análisis.
Sparhawk
@Sparhawk algo así. Creo que a ese nivel de salida, la CPU tendrá mucho tiempo para actualizar la pantalla sin reducir la velocidad de salida. Cuando el programa no hace más que escupir líneas sin pausa, los búferes de terminal se llenarán más rápido de lo que se puede actualizar la pantalla y crea un cuello de botella.
muru
3

Otra forma de acelerar un script es usar un intérprete de shell más rápido. Compare las velocidades de un bucle ocupado POSIX , ejecute en bash v4.4 , ksh v93u + 20120801 y dash v0.5.8 .

  1. bash:

    time echo 'n=0;while [ $n -lt 1000000 ] ; do \
                      echo $((n*n*n*n*n*n*n)) ; n=$((n+1)); 
                   done' | bash -s > /dev/null

    Salida:

    real    0m25.146s
    user    0m24.814s
    sys 0m0.272s
  2. ksh:

    time echo 'n=0;while [ $n -lt 1000000 ] ; do \
                      echo $((n*n*n*n*n*n*n)) ; n=$((n+1)); 
                   done' | ksh -s > /dev/null

    Salida:

    real    0m11.767s
    user    0m11.615s
    sys 0m0.010s
  3. dash:

    time echo 'n=0;while [ $n -lt 1000000 ] ; do \
                      echo $((n*n*n*n*n*n*n)) ; n=$((n+1)); 
                   done' | dash -s > /dev/null

    Salida:

    real    0m4.886s
    user    0m4.690s
    sys 0m0.184s

Un subconjunto de comandos en bashy kshson retrocompatibles con todos los comandos en dash. Un bashscript que solo usa comandos en ese subconjunto debería funcionar dash.

Algunas bashsecuencias de comandos que utilizan nuevas funciones se pueden convertir a otro intérprete. Si la bashsecuencia de comandos depende en gran medida de las características más nuevas, puede que no valga la pena molestarse: algunasbash características nuevas son mejoras que son más fáciles de codificar y más eficientes (a pesar de bashser generalmente más lentas), de modo que el dashequivalente (que podría implicar la ejecución) varios otros comandos), sería más lento.

En caso de duda, realice una prueba ...

agc
fuente
Entonces, para acelerar mi script bash, ¿necesito reescribirlos en bash o ksh?
Kingofkech
@ Kingofkech Puede ser que el código que escribió para bash sea el código ksh o dash correcto. Intenta cambiar el intérprete.
bli