Cómo ejecutar procesos paralelos y combinar salidas cuando ambos terminen

17

Tengo un script de shell bash en el que canalizo algunos datos a través de aproximadamente 5 o 6 programas diferentes y luego los resultados finales en un archivo delimitado por tabulaciones.

Luego hago lo mismo nuevamente para un conjunto de datos similar por separado y la salida a un segundo archivo.

Luego, ambos archivos se ingresan en otro programa para un análisis comparativo. por ejemplo, para simplificar

Data1 | this | that |theother | grep |sed | awk |whatever > Data1Res.csv
Data2 | this | that |theother | grep |sed | awk |whatever > Data2Res.csv
AnalysisProg -i Data1res.csv Data2res.csv

Mi pregunta es: ¿cómo puedo hacer que el paso 1 y el paso 2 se ejecuten al mismo tiempo (p. Ej., Usando &) pero solo iniciar el paso 3 (AnalysisProg) cuando ambos están completos?

Gracias

ps AnalysisProg no funcionará en una secuencia o quince.

Stephen Henderson
fuente
Por cierto, ¿está bien que uses scripts de Perl? Esto puede simplificar mucho el asunto para usted y puede implementar este postprocesamiento de manera muy eficiente y hacer que se ejecute en paralelo sin esfuerzo.
Bichoy
Perl ... no tanto, no :(
Stephen Henderson
1
Aquí demuestro cómo dividir la entrada a través de tuberías teey procesarla con dos grepprocesos concurrentes : unix.stackexchange.com/questions/120333/…
mikeserv
Y aquí demuestro cómo usar construcciones de shell simples para realizar un fondo completo de un proceso de la manera que nohuppodría pero manteniendo un medio de comunicación con el proceso: unix.stackexchange.com/questions/121253/…
mikeserv

Respuestas:

27

Uso wait. Por ejemplo:

Data1 ... > Data1Res.csv &
Data2 ... > Data2Res.csv &
wait
AnalysisProg

será:

  • ejecutar las tuberías Data1 y Data2 como trabajos en segundo plano
  • espera a que ambos terminen
  • Ejecute AnalysisProg.

Ver, por ejemplo, esta pregunta .

cxw
fuente
Gracias, eso se ve bien. Intentaré esto si lo anterior no funciona.
Stephen Henderson
Thx de nuevo, yo era una especie de conciencia de espera pero después de haber buscado en Google un poco estaba confundido a la forma en que trabajó con diferentes PID etc .. Me Daft sensación ahora veo que es sólo "espera"
Stephen Henderson
12

La respuesta de cxw es sin duda la solución preferible, si solo tiene 2 archivos. Si los 2 archivos son solo ejemplos y usted en realidad tiene 10000 archivos, entonces la solución '&' no funcionará, ya que eso sobrecargará su servidor. Para eso necesitas una herramienta como GNU Parallel:

ls Data* | parallel 'cat {} | this | that |theother | grep |sed | awk |whatever > {}res.csv
AnalysisProg -i *res.csv

Para obtener más información sobre GNU Parallel:

Ole Tange
fuente
Hola gracias En este momento tengo dos archivos, pero tengo 24 procesadores, así que me sentí tentado a intentar ejecutar muchos pares a la vez, aunque como no soy una persona de ciencias de la computación, no estoy claro si el cuello de botella en la lectura del disco haría que valiera la pena. tal vez lo chuparé y veré;)
Stephen Henderson
@StephenHenderson, dependiendo del tamaño, los archivos aún pueden estar en caché. Si la velocidad es crítica, puede usar tmpfs (y los archivos son <<< entonces su RAM).
Maciej Piechotka
1
@StephenHenderson El número de trabajos paralelos se puede ajustar con -j, así que intente -j4 y si el servidor no se sobrecarga, intente -j6, etc. Pero esté listo para presionar CTRL-C: GNU Parallel es una excelente herramienta para sobrecargar servidores rápidamente . También eche un vistazo a --load.
Ole Tange
1

Una forma de hacerlo podría ser algo como:

AnalysisProg <<PREPROCESS /dev/stdin
$( 
{   process1=$( pipe | line | 1 >&2 & echo $! )
    process2=$( pipe | line | 2 >&2 & echo $! )
    while ps -p $process1 $process2 >/dev/null; do
        sleep 1
    done
} 2>&1
)
#END
PREPROCESS

De esta manera, usted realiza un fondo de ambas canalizaciones pero aún espera a que terminen de ejecutarse antes de combinar su salida en stdin, que se evalúa en un documento aquí y se entrega a AnalysisProg. Si puede usar waitesto, es incluso mejor que el while psbucle, pero, dependiendo del shell, waitpuede objetar si le indica que espere un proceso que no es un hijo del shell actual.

También tenga en cuenta que el método anterior recopilará la salida, por lo que ambos procesos se escribirán a la vez. Si, en cambio, quisiera que se separaran, o se añadieran uno a otro, posiblemente podría hacer:

AnalysisProg 3<<PREPROCESS /dev/fd/3 /dev/stderr
$(
process1=$(... >&2 ...) 2>/dev/fd/3
...
} 3>/dev/fd/3 2>/dev/stderr
)

He demostrado estos conceptos antes. Probablemente las mejores demos estén aquí y aquí .

mikeserv
fuente
0

Intenta usar esto.

rm -f Data1Res.csv
rm -f Data2Res.csv
Data1 | this | that |theother | grep |sed | awk |whatever > Data1Res.csv &
Data2 | this | that |theother | grep |sed | awk |whatever > Data2Res.csv &
while true
do
  ps aux | grep -v grep | grep -i -E 'Data1Res.csv|Data2Res.csv' &> /dev/null
  if [ $? -ne 0 ]
  then
    AnalysisProg -i Data1res.csv Data2res.csv
    exit 0
  fi
done
Renan Vicente
fuente
Bueno, eso es pesado. ¿No es como reinventar waitla rueda?
John WH Smith