Pregunta

Para maximizar el uso de la CPU (corro cosas en un Debian Lenny en EC2) Tengo un script sencillo para iniciar trabajos en paralelo:

#!/bin/bash

for i in apache-200901*.log; do echo "Processing $i ..."; do_something_important; done &
for i in apache-200902*.log; do echo "Processing $i ..."; do_something_important; done &
for i in apache-200903*.log; do echo "Processing $i ..."; do_something_important; done &
for i in apache-200904*.log; do echo "Processing $i ..."; do_something_important; done &
...

Estoy bastante satisfecho con esta solución de trabajo, sin embargo no podía encontrar la manera de escribir código adicional que sólo se ejecuta una vez que todos los bucles se ha completado.

¿Hay una manera de conseguir el control de esta?

¿Fue útil?

Solución

Hay una bash orden interna para eso.

wait [n ...]
      Wait for each specified process and return its termination  sta‐
      tus.   Each  n  may be a process ID or a job specification; if a
      job spec is given, all processes  in  that  job’s  pipeline  are
      waited  for.  If n is not given, all currently active child pro‐
      cesses are waited for, and the return  status  is  zero.   If  n
      specifies  a  non-existent  process or job, the return status is
      127.  Otherwise, the return status is the  exit  status  of  the
      last process or job waited for.

Otros consejos

El uso paralelo de GNU hará que su escritura aún más corto y posiblemente más eficiente:

parallel 'echo "Processing "{}" ..."; do_something_important {}' ::: apache-*.log

Esto ejecutará un empleo por cada núcleo de CPU y seguir haciéndolo hasta que todos los archivos se procesan.

Su solución será básicamente dividir los trabajos en grupos antes de ejecutar. Aquí 32 puestos de trabajo en 4 grupos:

programación simple

Paralelo

GNU vez genera un nuevo proceso cuando uno termina - mantener la CPU activa y el consiguiente ahorro de tiempo:

GNU programación paralelo

Para obtener más información:

que tenía que hacer esto recientemente y terminó con la siguiente solución:

while true; do
  wait -n || {
    code="$?"
    ([[ $code = "127" ]] && exit 0 || exit "$code")
    break
  }
done;

Así es como funciona:

salidas wait -n tan pronto como uno de los muchos (potencialmente) ofertas de trabajo fondo salidas. Siempre se evalúa como verdadera y el bucle continúa hasta que:

  1. El código de salida 127: el último trabajo en segundo plano salido de forma satisfactoria. En ese caso, ignoramos el código de salida y salir de la sub-shell con código 0.
  2. Cualquiera de los fallidos trabajo en segundo plano. Acabamos de Salida de un sub-shell con ese código de salida.

Con set -e, esto garantizará que el script terminará pronto y pasar por el código de salida de cualquier trabajo en segundo plano fallado.

Esta es mi solución bruta:

function run_task {
        cmd=$1
        output=$2
        concurency=$3
        if [ -f ${output}.done ]; then
                # experiment already run
                echo "Command already run: $cmd. Found output $output"
                return
        fi
        count=`jobs -p | wc -l`
        echo "New active task #$count:  $cmd > $output"
        $cmd > $output && touch $output.done &
        stop=$(($count >= $concurency))
        while [ $stop -eq 1 ]; do
                echo "Waiting for $count worker threads..."
                sleep 1
                count=`jobs -p | wc -l`
                stop=$(($count > $concurency))
        done
}

La idea es utilizar "trabajos" para ver cuántos niños están activos en segundo plano y esperar a que este número se reduce (un niño salidas). Una vez que existe un niño, la siguiente tarea se puede iniciar.

Como se puede ver, también hay un poco de lógica adicional para evitar encontrarse con los mismos experimentos / comandos varias veces. Se hace el trabajo para mí .. Sin embargo, esta lógica podría ser omitidos o mejorarse aún más (por ejemplo, la verificación de las marcas de tiempo de creación de archivos, parámetros de entrada, etc.).

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top