0Pricing
DevOps Bootcamp · Lección

Orquestación de cargas de trabajo con GNU parallel

Distribuya grandes conjuntos de entradas entre núcleos con GNU parallel, espacios de trabajo y ordenación de resultados.

Orquestación de cargas de trabajo con GNU parallel es una lección gratuita de DevOps Bootcamp en CoddyKit. Esta es la lección 3 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de DevOps Bootcamp, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de DevOps Bootcamp incluye 4 lecciones en total.

Qué es GNU parallel y por qué usarlo

GNU parallel es una herramienta del shell que permite ejecutar trabajos en paralelo en una o varias máquinas. En lugar de procesar una lista grande de elementos uno por uno en un bucle for, parallel distribuye el trabajo entre todos los núcleos de CPU disponibles simultáneamente.

  • Velocidad: una tarea que tarda 8 minutos de forma secuencial puede terminar en aproximadamente 1 minuto en una máquina de 8 núcleos.
  • Simplicidad: acepta entradas desde stdin, archivos o listas de argumentos, sin necesidad de gestionar procesos manualmente.
  • Seguridad: mantiene separada la salida de los distintos trabajos; los resultados nunca se mezclan.

Instálelo con sudo apt install parallel (Debian/Ubuntu) o brew install parallel (macOS). Verifique la instalación con parallel --version.

Su primer comando parallel

La forma más sencilla de parallel lee elementos desde stdin y ejecuta un comando para cada uno. El marcador {} representa el elemento de entrada actual.

El ejemplo siguiente comprime cinco archivos de registro simultáneamente mediante gzip. Sin parallel, cada archivo se comprimiría uno después de otro. Con esta herramienta, se comprimen a la vez hasta N archivos (donde N = número de núcleos de CPU).

#!/usr/bin/env bash
# Create sample files first
for i in 1 2 3 4 5; do
  dd if=/dev/urandom bs=1M count=2 of="log_${i}.txt" 2>/dev/null
done

# Compress all of them in parallel
ls log_*.txt | parallel gzip {}

echo "Done. Compressed files:"
ls log_*.txt.gz

Controlar los puestos de trabajo con -j

De forma predeterminada, parallel ejecuta un trabajo por núcleo de CPU. Puede cambiar este comportamiento con la opción -j (o --jobs).

  • -j 4: ejecuta exactamente 4 trabajos a la vez
  • -j 0: ejecuta tantos trabajos como entradas haya (¡úselo con precaución!)
  • -j 200%: ejecuta el doble de trabajos que núcleos de CPU hay (resulta útil para cargas limitadas por E/S)
  • -j 50%: usa solo la mitad de los núcleos disponibles

Para tareas limitadas por la CPU, -j $(nproc) suele ser óptimo. Para tareas de E/S de red o de disco, puede superar con seguridad el número de núcleos, ya que los trabajos pasan la mayor parte del tiempo esperando.

#!/usr/bin/env bash
# Show how many cores are available
echo "CPU cores: $(nproc)"

# Run 8 sleep jobs but limit to 3 at a time
# -j 3 means at most 3 jobs run simultaneously
seq 1 8 | parallel -j 3 'echo "Starting job {}"; sleep 1; echo "Done job {}"'

echo "All jobs finished."

Leer entradas desde archivos y argumentos

parallel ofrece flexibilidad respecto al origen de su lista de entradas. No está limitado a usar una tubería desde stdin.

  • Desde un archivo: parallel -a urls.txt wget {}
  • Lista de argumentos integrada: parallel echo ::: apple banana cherry
  • Varias fuentes de argumentos (producto cartesiano): parallel echo {1}-{2} ::: a b c ::: 1 2: produce a-1, a-2, b-1, b-2, c-1, c-2
  • Explícitamente desde stdin: cat list.txt | parallel -j4 process {}

El separador ::: indica a parallel que use los valores siguientes como fuente de argumentos en lugar de leer desde stdin.

#!/usr/bin/env bash
# Inline list with :::
parallel echo 'Hello from {}' ::: Alice Bob Carol Dave

echo '---'

# Cartesian product: combine two lists
# Generates: dev-v1, dev-v2, prod-v1, prod-v2
parallel echo 'Deploy {1} to env {2}' ::: v1 v2 ::: dev prod

Marcadores: manipular tokens de entrada

parallel proporciona varias sustituciones de marcadores que permiten extraer automáticamente partes de la cadena de entrada, algo muy útil cuando las entradas son rutas de archivos.

  • {}: el elemento de entrada completo
  • {.}: la entrada sin su extensión de archivo (report.csv → report)
  • {/}: solo el nombre base (elimina la ruta del directorio)
  • {//}: solo la ruta del directorio
  • {/.}: nombre base sin extensión

Esto elimina la necesidad de llamar a basename / dirname dentro del comando del trabajo, lo que hace que las tuberías sean más limpias y rápidas.

#!/usr/bin/env bash
# Demonstrate placeholder substitutions
parallel --dry-run 'convert {} -resize 800x600 {.}_thumb.jpg' \
  ::: /photos/vacation/beach.png /photos/work/team.png

# {.}  strips extension: /photos/vacation/beach
# Result command shown (--dry-run does NOT execute):
#  convert /photos/vacation/beach.png -resize 800x600 /photos/vacation/beach_thumb.jpg
#  convert /photos/work/team.png      -resize 800x600 /photos/work/team_thumb.jpg
echo 'No files were changed (dry run)'

Mantener el orden de la salida con --keep-order

Cuando los trabajos terminan en momentos distintos, su salida stdout aparece en el orden en que finalizan. Esto puede dificultar la lectura de los registros y hacer que el análisis posterior no sea fiable.

Dos opciones controlan el orden de la salida:

  • --keep-order (-k): imprime la salida de cada trabajo en el mismo orden que la entrada, aunque un trabajo posterior termine primero. La salida se almacena en búfer hasta que terminan los trabajos anteriores.
  • --line-buffer: una solución intermedia: muestra las líneas completas a medida que llegan, sin esperar a que termine el trabajo, pero nunca mezcla líneas escritas parcialmente.

Use -k cuando el consumidor posterior espere los resultados en el orden de entrada (por ejemplo, al crear un informe ordenado). Omítalo cuando el orden no importe y quiera ver los resultados lo antes posible.

#!/usr/bin/env bash
# Without -k: output order is unpredictable
echo '--- Without --keep-order ---'
seq 5 1 1 | parallel 'sleep 0.$((RANDOM % 5)); echo "Result for {}"'

echo

# With -k: output always appears as 5, 4, 3, 2, 1
echo '--- With --keep-order (-k) ---'
seq 5 1 1 | parallel -k 'sleep 0.$((RANDOM % 5)); echo "Result for {}"'

Agrupar la salida para evitar el intercalado

Incluso con la salida ordenada, si un trabajo imprime varias líneas, estas pueden intercalarse con las líneas de otro trabajo que se ejecute al mismo tiempo. parallel lo resuelve automáticamente almacenando en búfer toda la salida estándar y la salida de error de cada trabajo, y después imprimiéndolas como un único bloque atómico cuando el trabajo termina.

Este comportamiento está activado de forma predeterminada. Puede desactivarlo con --ungroup si necesita transmitir la salida en tiempo real (por ejemplo, en trabajos de larga duración con barras de progreso), pero entonces vuelve a ser posible que las líneas se intercalen.

  • Predeterminado: la salida se agrupa por trabajo, lo que permite analizarla de forma segura.
  • --ungroup: la salida se transmite en tiempo real, lo que resulta útil para la supervisión interactiva.
  • --line-buffer: opción intermedia; las líneas nunca se dividen, pero los trabajos pueden intercalarse en los límites entre líneas.

Pasar argumentos dentro de funciones de shell

A veces, el trabajo que desea paralelizar es más que un único comando: se trata de una función de shell de varios pasos. Puede pasar una función a parallel usando export -f combinado con env_parallel, o llamando directamente a bash -c.

El enfoque portable más seguro para trabajos complejos es el patrón bash -c '...'. El marcador de posición {} se pasa como $1 cuando se termina con _ {}.

#!/usr/bin/env bash
# Define a multi-step processing function
process_item() {
  local item="$1"
  echo "[START] $item"
  # Simulate two steps
  sleep 0.2
  local result=$(echo "$item" | tr '[:lower:]' '[:upper:]')
  echo "[END]   $item -> $result"
}

export -f process_item

# Run the function in parallel for each input
echo 'alpha beta gamma delta epsilon' | tr ' ' '\n' \
  | parallel -j 3 process_item {}

Limitar la tasa y reintentar con --delay y --retries

Al acceder en paralelo a servicios externos (API, servidores remotos o bases de datos), a menudo necesita limitar la tasa y tolerar errores.

  • --delay N — espera N segundos entre el inicio de cada trabajo nuevo (se permiten valores fraccionarios como 0.5). Evita saturar un servicio.
  • --retries N — si un trabajo termina con un estado distinto de cero, lo reintenta hasta N veces antes de abandonar. Cada reintento cuenta como un nuevo puesto de trabajo.
  • --timeout N — termina un trabajo si se ejecuta durante más de N segundos. Combinado con --retries, permite gestionar correctamente los trabajos bloqueados.

Ejemplo: descargar 50 URL con como máximo 4 conexiones simultáneas, un retardo de 0.5 s entre inicios y 3 reintentos en caso de error.

#!/usr/bin/env bash
# Simulate downloading URLs with throttling and retries
# (using echo instead of curl so this is self-contained)

download_url() {
  local url="$1"
  # Randomly fail ~30% of the time to demo --retries
  if (( RANDOM % 10 < 3 )); then
    echo "FAIL: $url" >&2
    return 1
  fi
  echo "OK:   $url downloaded"
}

export -f download_url

printf 'https://example.com/file%d\n' $(seq 1 10) \
  | parallel -j 4 --delay 0.2 --retries 3 download_url {}

echo 'All downloads attempted.'

Distribuir el trabajo entre hosts remotos con --sshloginfile

parallel puede distribuir trabajos de forma transparente a máquinas remotas mediante SSH, lo que lo convierte en una herramienta ligera de computación en clúster sin necesidad de software especial para clústeres.

  • --sshlogin user@host — ejecuta trabajos en un host remoto específico.
  • --sshloginfile machines.txt — lee una lista de hosts desde un archivo (uno por línea). Use : como entrada especial para utilizar también la máquina local.
  • --transfer — copia el archivo de entrada al host remoto antes de procesarlo.
  • --return {} — copia el archivo de resultados de vuelta cuando termina el trabajo.
  • --cleanup — elimina del host remoto los archivos transferidos después de recuperarlos.

El host remoto debe tener parallel instalado y la autenticación mediante claves SSH configurada (sin solicitudes de contraseña).

Informes de progreso y registro

En cargas de trabajo de larga duración, es esencial supervisar el progreso y diagnosticar los errores posteriormente.

  • --progress — muestra en tiempo real una línea resumida con el número de trabajos en ejecución, completados y pendientes.
  • --eta — estima el tiempo restante basándose en la duración media de los trabajos hasta el momento.
  • --joblog results.log — escribe un archivo de registro separado por tabuladores, con una fila por cada trabajo completado, incluido el código de salida, el tiempo de ejecución y el comando ejecutado. Es muy útil para auditar errores.
  • --resume --joblog results.log — omite los trabajos que ya aparecen (con código de salida 0) en el archivo de registro. Si una ejecución por lotes se interrumpe, puede reanudarla sin repetir el trabajo realizado correctamente.

La combinación de --joblog y --resume es una de las funciones más potentes de GNU parallel para crear canalizaciones de producción resistentes.

#!/usr/bin/env bash
LOGFILE="/tmp/parallel_demo_$$.log"

# Run jobs and record results to a log
seq 1 12 | parallel \
  --jobs 4 \
  --progress \
  --joblog "$LOGFILE" \
  'sleep 0.1; echo "Processed item {}"'

echo
echo '=== Job Log (first 5 entries) ==='
head -6 "$LOGFILE"

# Show only failed jobs (exit value != 0)
echo '=== Failed jobs ==='
awk 'NR>1 && $7 != 0 { print $0 }' "$LOGFILE" || echo '(none)'

rm -f "$LOGFILE"

Comprobación de conocimientos: opciones de puestos de trabajo

Compruebe que comprende cómo parallel controla la concurrencia.

Repaso de la lección: orquestar cargas de trabajo con GNU parallel

Ha aprendido las herramientas fundamentales para distribuir grandes conjuntos de entradas entre los núcleos de la CPU con GNU parallel. Esto es lo más importante:

  • Uso básico: canalice una lista a parallel command {}; {} se sustituye por cada elemento de entrada.
  • Puestos de trabajo (-j): controle la concurrencia con precisión: use el número de núcleos para trabajos limitados por la CPU y porcentajes más altos para trabajos limitados por la E/S.
  • Marcadores de posición ({.}, {/}, {//}, {/.}) permiten extraer limpiamente los componentes de las rutas sin comandos adicionales.
  • Control de la salida: -k conserva el orden de entrada; la agrupación predeterminada evita el intercalado de líneas; --ungroup proporciona transmisión en tiempo real.
  • Resiliencia: --retries, --timeout y --delay hacen que las canalizaciones paralelas sean resistentes a trabajos inestables y a los límites de tasa.
  • Auditabilidad: --joblog registra el resultado de cada trabajo; --resume permite continuar desde el punto en que se interrumpió la ejecución.
  • Escalado horizontal: --sshloginfile distribuye trabajos a máquinas remotas mediante SSH sin la sobrecarga de un clúster.

Dominar estas opciones convierte parallel en un orquestador de cargas de trabajo listo para producción, integrado directamente en su shell.

Preguntas frecuentes

¿La lección «Orquestación de cargas de trabajo con GNU parallel» es gratis?

Sí — el texto completo de «Orquestación de cargas de trabajo con GNU parallel» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de DevOps Bootcamp, actualiza a CoddyKit PRO. El curso de DevOps Bootcamp incluye 4 lecciones en total.

¿Qué aprenderé en «Orquestación de cargas de trabajo con GNU parallel»?

Distribuya grandes conjuntos de entradas entre núcleos con GNU parallel, espacios de trabajo y ordenación de resultados. Practicas DevOps Bootcamp con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.

¿Necesito experiencia previa para empezar DevOps Bootcamp?

No se requiere experiencia previa. DevOps Bootcamp en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 3 de 4.

¿Cuánto tiempo toma la lección «Orquestación de cargas de trabajo con GNU parallel»?

La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.

¿Puedo escribir y ejecutar código en esta lección de DevOps Bootcamp?

Sí. Cada lección de DevOps Bootcamp incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.

Todas las lecciones de este curso

  1. Perfilado de scripts y cómo evitar subshells innecesarios
  2. Paralelismo con xargs -P y trabajos en segundo plano
  3. Orquestación de cargas de trabajo con GNU parallel
  4. Pipelines de streaming y tuberías con nombre para mejorar el rendimiento
← Volver a DevOps Bootcamp