scripts script programas parametros funciones for ejemplos con comando bash parallel-processing

programas - scripts bash ejemplos



¿Cómo ejecutar la función dada en Bash en paralelo? (3)

Ha habido algunas preguntas similares, pero mi problema no es "ejecutar varios programas en paralelo", lo que se puede hacer de forma trivial con parallel o xargs .

Necesito paralelizar las funciones de Bash.

Imaginemos un código como este:

for i in "${list[@]}" do for j in "${other[@]}" do # some processing in here - 20-30 lines of almost pure bash done done

Parte del procesamiento requiere llamadas a programas externos.

Me gustaría ejecutar algunas (4-10) tareas, cada una de ellas ejecutando diferentes $i . El número total de elementos en $ list es> 500.

Sé que puedo poner todo el bucle for j ... done en un script externo, y simplemente llamar a este programa en paralelo, pero ¿es posible hacerlo sin dividir la funcionalidad entre dos programas separados?


Edición: Por favor considere la respuesta de Ole en su lugar.

En lugar de un script separado, puedes poner tu código en una función bash separada. Luego puedes exportarlo y ejecutarlo a través de xargs:

#!/bin/bash dowork() { sleep $((RANDOM % 10 + 1)) echo "Processing i=$1, j=$2" } export -f dowork for i in "${list[@]}" do for j in "${other[@]}" do printf "%s/0%s/0" "$i" "$j" done done | xargs -0 -n 2 -P 4 bash -c ''dowork "$@"'' --


Solución para ejecutar comandos multilínea en paralelo:

for ...your_loop...; do test "$(jobs | wc -l)" -ge 8 && wait -n || true # wait if needed { any bash commands here } & done

En tu caso:

for i in "${list[@]}" do for j in "${other[@]}" do test "$(jobs | wc -l)" -ge 8 && wait -n || true { your multi-line commands here } & done done

Si hay 8 trabajos de bash ya en ejecución, la wait esperará a que se complete al menos un trabajo. Si / cuando hay menos trabajos, se inician los nuevos de forma asíncrona.

Beneficios de este enfoque:

  1. Es muy fácil para comandos multilínea. Todas sus variables se "capturan" automáticamente en el alcance, sin necesidad de pasarlas como argumentos
  2. Es relativamente rápido. Compare esto, por ejemplo, con el paralelo (estoy citando al man oficial):

    el paralelo es lento en el inicio, aproximadamente 250 ms la primera vez y 150 ms después de eso.

  3. Solo necesita bash para trabajar.

Desventajas:

  1. Existe la posibilidad de que haya 8 trabajos cuando los contamos, pero menos cuando comenzamos a esperar. (Ocurre si un trabajo termina en esos milisegundos entre los dos comandos). Esto puede hacer que wait con menos trabajos que los requeridos. Sin embargo, se reanudará cuando al menos un trabajo se complete, o inmediatamente si hay 0 trabajos en ejecución (en este caso, wait -n cierra inmediatamente).
  2. Si ya tiene algunos comandos que se ejecutan de forma asíncrona ( & ) dentro del mismo script bash, tendrá menos procesos de trabajo en el bucle.

sem es parte de GNU Parallel y está hecho para este tipo de situación.

for i in "${list[@]}" do for j in "${other[@]}" do # some processing in here - 20-30 lines of almost pure bash sem -j 4 dolong task done done

Si le gusta la función, GNU Parallel puede hacer el doble para bucle de una sola vez:

dowork() { echo "Starting i=$1, j=$2" sleep 5 echo "Done i=$1, j=$2" } export -f dowork parallel dowork ::: "${list[@]}" ::: "${other[@]}"