Saltar al contenido

Paralelizar un Bash FOR Loop

Posteriormente a buscar en varios repositorios y páginas al final nos hemos encontrado la respuesta que te compartimos aquí.

Solución:

Tarea de muestra

task()
   sleep 0.5; echo "$1";

Ejecuciones secuenciales

for thing in a b c d e f g; do 
   task "$thing"
done

carreras paralelas

for thing in a b c d e f g; do 
  task "$thing" &
done

Corridas paralelas en lotes de N-procesos

N=4
(
for thing in a b c d e f g; do 
   ((i=i%N)); ((i++==0)) && wait
   task "$thing" & 
done
)

También es posible usar FIFO como semáforos y usarlos para garantizar que se generen nuevos procesos lo antes posible y que no se ejecuten más de N procesos al mismo tiempo. Pero requiere más código.

N procesos con un semáforo basado en FIFO:

# initialize a semaphore with a given number of tokens
open_sem()
    mkfifo pipe-$$
    exec 3<>pipe-$$
    rm pipe-$$
    local i=$1
    for((;i>0;i--)); do
        printf %s 000 >&3
    done


# run the given command asynchronously and pop/push tokens
run_with_lock()

N=4
open_sem $N
for thing in a..g; do
    run_with_lock task $thing
done 

Explicación:

Usamos el descriptor de archivo 3 como un semáforo presionando (=printf) y hacer estallar (=read) fichas ('000'). Al presionar el código de retorno de las tareas ejecutadas, podemos abortar si algo salió mal.

¿Por qué no los bifurca (también conocido como fondo)?

foo () 
    local run=$1
    fsl5.0-flirt -in $kar"deformed.nii.gz" -ref normtemp.nii.gz -omat $run".norm1.mat" -bins 256 -cost corratio -searchrx -90 90 -searchry -90 90 -searchrz -90 90 -dof 12 
    fsl5.0-flirt -in $run".poststats.nii.gz" -ref $kar"deformed.nii.gz" -omat $run".norm2.mat" -bins 256 -cost corratio -searchrx -90 90 -searchry -90 90 -searchrz -90 90 -dof 12 
    fsl5.0-convert_xfm -concat $run".norm1.mat" -omat $run".norm.mat" $run".norm2.mat"
    fsl5.0-flirt -in $run".poststats.nii.gz" -ref normtemp.nii.gz -out $PWD/normFunc/$run".norm.nii.gz" -applyxfm -init $run".norm.mat" -interp trilinear


for run in $runList; do foo "$run" & done

En caso de que no esté claro, la parte importante está aquí:

for run in $runList; do foo "$run" & done
                                   ^

Haciendo que la función se ejecute en un shell bifurcado en segundo plano. Eso es paralelo.

for stuff in things
do
( something
  with
  stuff ) &
done
wait # for all the something with stuff

Si realmente funciona depende de tus comandos; No estoy familiarizado con ellos. El rm *.mat parece un poco propenso a conflictos si se ejecuta en paralelo…

Al final de la post puedes encontrar las críticas de otros desarrolladores, tú de igual manera tienes la habilidad dejar el tuyo si te apetece.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *