Ejecutar programas en paralelo usando xargs

85

Actualmente tengo el script actual.

#!/bin/bash
# script.sh

for i in {0..99}; do
   script-to-run.sh input/ output/ $i
done

Deseo ejecutarlo en paralelo usando xargs. Yo he tratado

script.sh | xargs -P8

Pero hacer lo anterior solo se ejecuta una vez a la vez. No tuve suerte con -n8 también. Agregar & al final de la línea que se ejecutará en el script for loop intentaría ejecutar el script 99 veces a la vez. ¿Cómo ejecuto el ciclo solo 8 a la vez, hasta 100 en total?

Olivier
fuente
Eso es lo que inicialmente quería hacer, pero tuve que recurrir a xargs porque estoy en Windows. No pude ejecutar GNU Parallel en Windows
Olivier
¿Ese guión se llama a sí mismo o simplemente confundió los nombres cuando preguntó aquí?
Etan Reisner
Lo siento, debería llamar a otro script. Lo arreglaré
Olivier
La respuesta a stackoverflow.com/questions/3321738/… es relevante aquí.
Etan Reisner

Respuestas:

128

Desde la xargspágina del manual:

Esta página de manual documenta la versión GNU de xargs. xargs lee elementos de la entrada estándar, delimitados por espacios en blanco (que pueden protegerse con comillas dobles o simples o una barra invertida) o nuevas líneas, y ejecuta el comando (el predeterminado es / bin / echo) una o más veces con cualquier argumento inicial seguido por elementos leídos de la entrada estándar. Las líneas en blanco de la entrada estándar se ignoran.

Lo que significa que, para su ejemplo, xargsestá esperando y recopilando toda la salida de su script y luego ejecutándose echo <that output>. No es exactamente tan útil ni lo que querías.

El -nargumento es cuántos elementos de la entrada se deben usar con cada comando que se ejecuta (nada, por sí mismo, sobre el paralelismo aquí).

Para hacer lo que quieras xargs, necesitarás hacer algo más parecido a esto (no probado):

printf %s\\n {0..99} | xargs -n 1 -P 8 script-to-run.sh input/ output/

Que se descompone así.

  • printf %s\\n {0..99}- Imprime un número por línea desde 0hasta 99.
  • correr xargs
    • tomando como máximo un argumento por línea de comando de ejecución
    • y ejecutar hasta ocho procesos a la vez
Etan Reisner
fuente
7
En realidad, no es necesario poner los argumentos en líneas separadas; xargs divisiones de palabras. Entonces echo {0..99} |funcionaría igual de bien. <<<{0..99}no parece funcionar; aunque <<<wordestá documentado como palabra de expansión de llaves, no lo hace con ninguna versión de bash que tenga a mano.
rici
1
@rici Parece un error de documentación, especialmente porque la documentación de Here Documents no menciona la expansión de llaves (y tampoco ocurre allí en una prueba rápida), aunque tampoco mencionan la expansión de tilde (lo que no sucede porque <<pero lo hace por <<<eso *shrug*). Las expansiones que suceden y no ocurren aquí en documentos y aquí cadenas son un poco extrañas para mi mente.
Etan Reisner
1
¿Cómo se pueden separar los resultados de diferentes ejecuciones con, por ejemplo, nuevas líneas?
nirvana-msu
3
Demostración: time head -12 <(yes "1") | xargs -n1 -P4 sleepejecutará 12 sleep 1comandos, 4 en paralelo. El comando tardará 3 segundos.
Walter A
66

Con GNU Parallel haría:

parallel script-to-run.sh input/ output/ {} ::: {0..99}

Agregue -P8si no desea ejecutar un trabajo por núcleo de CPU.

En el lado opuesto xargs, hará lo correcto, incluso si la entrada contiene espacio, 'o "(aunque no es el caso aquí). También se asegura de que la salida de diferentes trabajos no se mezclen, por lo que si usa la salida, está garantizado que no obtendrá media línea de dos trabajos diferentes.

GNU Parallel es un paralelizador general y facilita la ejecución de trabajos en paralelo en la misma máquina o en varias máquinas a las que tiene acceso ssh.

Si tiene 32 trabajos diferentes que desea ejecutar en 4 CPU, una forma sencilla de paralelizar es ejecutar 8 trabajos en cada CPU:

Programación sencilla

GNU Parallel, en cambio, genera un nuevo proceso cuando uno termina, manteniendo las CPU activas y ahorrando tiempo:

Programación paralela de GNU

Instalación

Si GNU Parallel no está empaquetado para su distribución, puede realizar una instalación personal, que no requiere acceso de root. Se puede hacer en 10 segundos haciendo esto:

$ (wget -O - pi.dk/3 || lynx -source pi.dk/3 || curl pi.dk/3/ || \
   fetch -o - http://pi.dk/3 ) > install.sh
$ sha1sum install.sh | grep 67bd7bc7dc20aff99eb8f1266574dadb
12345678 67bd7bc7 dc20aff9 9eb8f126 6574dadb
$ md5sum install.sh | grep b7a15cdbb07fb6e11b0338577bc1780f
b7a15cdb b07fb6e1 1b033857 7bc1780f
$ sha512sum install.sh | grep 186000b62b66969d7506ca4f885e0c80e02a22444
6f25960b d4b90cf6 ba5b76de c1acdf39 f3d24249 72930394 a4164351 93a7668d
21ff9839 6f920be5 186000b6 2b66969d 7506ca4f 885e0c80 e02a2244 40e8a43f
$ bash install.sh

Para conocer otras opciones de instalación, consulte http://git.savannah.gnu.org/cgit/parallel.git/tree/README

Aprende más

Ver más ejemplos: http://www.gnu.org/software/parallel/man.html

Vea los videos de introducción: https://www.youtube.com/playlist?list=PL284C9FF2488BC6D1

Siga el tutorial: http://www.gnu.org/software/parallel/parallel_tutorial.html

Regístrese en la lista de correo electrónico para obtener soporte: https://lists.gnu.org/mailman/listinfo/parallel

Ole Tange
fuente
19
Esto no responde a la pregunta, ni indica por qué xargs no puede lograr lo mismo.
张 实 唯
8
downvote porque xarg para mí hace exactamente lo que muestra la segunda imagen.
noonex
3
@noonex ¿Sabe que no todo el mundo usa la versión de xargs que usted usa y que -P no está en todas las versiones de xargs?
Ole Tange
19
Quizás no todos sepan que esta respuesta la proporciona el autor de GNU paralelos.
izkeros
1
Votado en contra debido a un anuncio claro en un software que no se ejecuta correctamente como se describe en los primeros intentos, debido a un mensaje interactivo que estropea la mayoría de los scripts.
Daniel Sorichetti