Multi-Threading / Forking en un script bash

9

He escrito un script bash que está en el siguiente formato:

#!/bin/bash
start=$(date +%s)
inFile="input.txt"
outFile="output.csv"

rm -f $inFile $outFile

while read line
do

    -- Block of Commands

done < "$inFile"

end=$(date +%s)

runtime=$((end-start))

echo "Program has finished execution in $runtime seconds."

El whilebucle leerá $inFile, realizará alguna actividad en la línea y volcará el resultado $outFile.

Como $inFiletiene más de 3500 líneas de longitud, el script tardaría entre 6 y 7 horas en ejecutarse por completo. Para minimizar este tiempo, estoy planeando usar subprocesos múltiples o bifurcación en este script. Si creo 8 procesos secundarios, 8 líneas de la $inFilese procesarán simultáneamente.

¿Cómo se puede hacer esto?

Mandar Shinde
fuente
Tenga cuidado: diferentes scripts necesitarán escribir en diferentes archivos. ¡Además, su secuencia de comandos como está escrita elimina el archivo de entrada como la primera acción!
pjc50

Respuestas:

10

GNUparallel está hecho para este tipo de cosas. Puede ejecutar su script muchas veces a la vez, con diferentes datos de su entrada canalizados para cada uno:

cat input.txt | parallel --pipe your-script.sh

De forma predeterminada, generará procesos de acuerdo con la cantidad de procesadores en su sistema, pero puede personalizarlo con -j N.

Un truco particularmente bueno es la función de envoltura shebang. Si cambia la primera línea de su script Bash a:

#!/usr/bin/parallel --shebang-wrap --pipe /bin/bash

y alimentar sus datos en la entrada estándar, entonces todo sucederá automáticamente. Esto es menos útil cuando tiene un código de limpieza que debe ejecutarse al final, lo cual puede hacer.

Hay un par de cosas a tener en cuenta. Una es que dividirá su entrada en fragmentos secuenciales y los usará uno a la vez, no intercala líneas. La otra es que esos fragmentos se dividen por tamaño, sin importar cuántos registros hay. Puede usar --block Npara establecer un tamaño de bloque diferente en bytes. En su caso, no más de una octava parte del tamaño del archivo debería ser lo correcto. Su archivo parece que podría ser lo suficientemente pequeño como para terminar todo en un solo bloque de lo contrario, lo que sería contrario al propósito.

Hay muchas opciones para casos de uso diferentes en particular, pero el tutorial cubre las cosas bastante bien. Las opciones que también podrían interesarle incluyen incluir --round-robiny --group.

Michael Homer
fuente
1
¿Probaste esa línea shebang? Los shebangs con múltiples argumentos son inportables. En Linux, #!a b cdará como resultado ["b c"], mientras que en algunos otros sistemas, dará como resultado ["b", "c"].
nyuszika7h
1
Analiza sus propios argumentos cuando se usa de esta manera (de lo contrario, la opción no sería muy útil).
Michael Homer
@MichaelHomer Necesito usar GNU parallelpara raspar páginas HTML. ¿Podrían leer
Swatesh Pakhare el