Tengo tres tipos de datos que están en diferentes formatos; Para cada tipo de datos, hay un script de Python que lo transforma en un único formato unificado.
Este script de Python es lento y está vinculado a la CPU (a un solo núcleo en una máquina multinúcleo), por lo que quiero ejecutar tres instancias del mismo, una para cada tipo de datos, y combinar su salida para pasarlo sort
. Básicamente, equivalente a esto:
{ ./handle_1.py; ./handle_2.py; ./handle_3.py } | sort -n
Pero con los tres scripts ejecutándose en paralelo.
Encontré esta pregunta en la que GNU split
se estaba utilizando para hacer un round-robin de una secuencia estándar entre n instancias de un script que maneja la secuencia.
Desde la página man dividida:
-n, --number=CHUNKS
generate CHUNKS output files. See below
CHUNKS may be:
N split into N files based on size of input
K/N output Kth of N to stdout
l/N split into N files without splitting lines
l/K/N output Kth of N to stdout without splitting lines
r/N like 'l' but use round robin distributio
Entonces el r/N
comando implica " sin dividir líneas ".
En base a esto, parece que la siguiente solución debería ser factible:
split -n r/3 -u --filter="./choose_script" << EOF
> 1
> 2
> 3
> EOF
Donde choose_script
hace esto:
#!/bin/bash
{ read x; ./handle_$x.py; }
Desafortunadamente, veo algunas líneas entremezcladas, y muchas líneas nuevas que no deberían estar allí.
Por ejemplo, si reemplazo mis scripts de Python con algunos scripts de bash simples que hacen esto:
#!/bin/bash
# ./handle_1.sh
while true; echo "1-$RANDOM"; done;
.
#!/bin/bash
# ./handle_2.sh
while true; echo "2-$RANDOM"; done;
.
#!/bin/bash
# ./handle_3.sh
while true; echo "3-$RANDOM"; done;
Veo esta salida:
1-8394
2-11238
2-22757
1-723
2-6669
3-3690
2-892
2-312511-24152
2-9317
3-5981
Esto es molesto: según el extracto de la página de manual que pegué anteriormente, debería mantener la integridad de la línea.
Obviamente, funciona si elimino el -u
argumento, pero luego está almacenado en el búfer y me quedaré sin memoria, ya que amortigua la salida de todos menos uno de los scripts.
Si alguien tiene alguna idea aquí, sería muy apreciado. Estoy fuera de mi profundidad aquí.
coproc
builtin en bash, aunque realmente no veo cómo se aplica.job1.py > file1 & job2.py > file 2 & job3.py > file3 ; wait ; sort -n file1 file2 file3
?Respuestas:
Intente usar la opción -u de GNU paralela.
Esto los ejecuta en paralelo, sin amortiguar la totalidad de ningún proceso.
fuente
X
deIX
decir-I
que X será la bandera para reemplazar, o está aplicando la-X
bandera, que aparentemente también tiene un significado relevante?parallel -u -X ./handle_{}.sh ::: "1" "2" "3"
y, desafortunadamente, todavía veo algunos cambios de salida.parallel -u ./handle_{}.sh
, pero prefiero cambiarlo, ya que los corchetes también tienen el significado de unir comandos (como en su pregunta).Tratar:
Si
handle_1.py
toma un nombre de archivo:No desea que la salida se mezcle, así que no use -u.
Si desea mantener el orden (por lo que toda la salida de handle_1 es anterior a handle_2 y, por lo tanto, puede evitar la clasificación):
Si aún desea ordenarlo, puede paralelizar el orden y utilizar
sort -m
:Establezca $ TMPDIR en un directorio que sea lo suficientemente grande como para contener la salida.
fuente
Tal vez me estoy perdiendo algo, pero no puedes simplemente hacer:
Si desea que las líneas de cada proceso no se intercalen, lo más fácil es asegurarse de que el proceso mismo las escriba por completo y posiblemente deshabilite el almacenamiento en búfer de salida, ya
write
que se garantiza que los valores atómicos de una tubería sean atómicos siempre que no sean más grandes quePIPE_BUF
. Por ejemplo, usted podría asegurarse de que hace búfer de salida a la utilizaciónstdio
y la llamadafflush
o lo que es el equivalente enpython
después de una o unas pocas líneas se han escrito.Si no puede modificar los scripts de Python, puede hacer lo siguiente:
(con GNU grep) o:
(Consulte las notas en los comentarios a continuación si la salida de los comandos no es texto)
Y hacer:
Otra opción para evitar esos 3
lb
procesos es tener tres canales para un comando que useselect
/poll
para ver de dónde proviene alguna salida y alimentarla ensort
línea, pero requiere un poco de programación.fuente
wait
allí, creo.sort -n
permanecerá hasta que todos los programas que tienen un fd abierto hayan salido.La respuesta de Flowbok fue la solución correcta. Curiosamente, la salida de GNU
parallel
se destruye si se envía directamente a un archivo, pero no si va a un tty.Afortunadamente,
script -c
está disponible para imitar un tty.Todavía quedan los tres guiones:
.
.
Luego hay un archivo que encapsula la llamada al paralelo:
Y luego lo llamo así:
Las líneas en la salida se mezclan línea por línea entre la salida de los diferentes scripts, pero no se mutilan ni se intercalan en una línea determinada.
Comportamiento extraño de
parallel
: puedo presentar un informe de error.fuente