
Tengo una gran cantidad de archivos grandes (cientos de archivos, cientos de MB cada uno) que necesito canalizar a través de varios programas para filtrarlos y convertirlos. Estoy aprovechando múltiples núcleos de CPU, por lo que estoy ejecutando varias instancias de la misma canalización en cada archivo (podrían ser hasta cien núcleos y podría usar ssh como parte de la canalización, en caso de que eso haga alguna diferencia para el respuesta). Quiero monitorear cada tubería y lo estoy usando pv
para eso. Aquí hay un ejemplo mínimo de lo que tengo:
$ pv file-001.gz | gunzip | xz > file-001.xz
1.58GB 0:00:02 [ 713MB/s] [=================================>] 100%
En realidad, también hago varias otras cosas en la tubería, incluido pasar datos a otras máquinas a través de ssh y canalizarlos a través de filtros en esas máquinas, pero la tubería siempre termina con una redirección a un nuevo archivo en el host principal. Además, ninguna etapa de la tubería requiere todo el conjunto de datos; pueden operar línea por línea o fragmento por fragmento.
Actualmente, necesito una ventana de terminal separada para cada instancia de la tubería. Lo que me gustaría hacer es iniciar n instancias paralelas de la tubería en un único terminal/shell y obtener el resultado de cada instancia pv en una línea propia. Algo como esto:
1.48GB 0:00:54 [ 704MB/s] [===============================> ] 97% ETA 00:00:06
1.58GB 0:01:00 [ 713MB/s] [=================================>] 100%
0.75GB 0:00:31 [ 709MB/s] [================> ] 50% ETA 00:00:29
El valor de n sería el número de líneas que puedo incluir en una ventana de terminal, digamos entre 3 y 50 aproximadamente. El formato exacto del informe de progreso no es importante, siempre que incluya la velocidad, el porcentaje realizado, el tiempo transcurrido y el tiempo restante estimado. Tampoco es importante que use pv
, está bien usar algún otro programa siempre que pueda instalarlo fácilmente o simplemente un shell (bash, preferiblemente). Sin embargo, lo importante es que el método puede manejar la rotura ocasional de una tubería en caso de que una parte de la tubería falle por algún motivo. También me gustaría iniciar nuevos trabajos cada vez que finaliza un trabajo (con éxito o no) y todavía quedan archivos sin procesar.
¿Alguna idea sobre cómo hacer esto?
Tenga en cuenta que ya lo he probadoParalelo GNU, pero sus características ssh parecen suponer que cada archivo de entrada se transfiere primero al host remoto, luego se procesa y luego el resultado se transfiere nuevamente, lo cual quiero evitar debido a la cantidad de datos involucrados y la cantidad limitada de espacio en cada procesamiento. nodo.
Respuesta1
¿Alguna idea sobre cómo hacer esto?
No.
pv tiene opciones -c y -N que deberían permitirle hacer lo que quiera
$ pv -cN source access.log | gzip | pv -cN gzip > access.log.gz
source: 760MB 0:00:15 [37.4MB/s] [=> ] 19% ETA 0:01:02
gzip: 34.5MB 0:00:15 [1.74MB/s] [ <=> ]
pero no veo cómo aplicar esa característica a múltiples canalizaciones
Sin embargo, si miras la página de manual de pv verás esto
(tar cf - . \
| pv -n -s $(du -sb . | awk '{print $1}') \
| gzip -9 > out.tgz) 2>&1 \
| dialog --gauge 'Progress' 7 70
Por lo tanto, podría ampliar esto para ejecutar varias tareas en paralelo siempre que sea aceptable ver el progreso en un grupo de ventanas pequeñas. Probaría Xdialog.
Actualmente, necesito una ventana de terminal separada para cada instancia de la tubería.
Mi punto principal es que no es necesario que abras interactivamente muchas ventanas de terminal, puedes hacer que un script abra muchos cuadros de diálogo.
Respuesta2
¿Buscaste --pipe
GNU Parallel?
cat bigfiles* | pv | parallel --pipe -S server1,server2 'cat | process_pipe'
(gato incluido para énfasis)
El tamaño de bloque predeterminado es de 1 MB, que se puede ajustar con --block.
-- editar para correspondencia 1-1 --
Según lo anterior, puede obtener correspondencia 1-1 como esta:
parallel --eta "cat {} | parallel --pipe -S server1,server2 'cat | process_pipe' > {}.out" ::: bigfiles*
(gato incluido para énfasis)
No es del todo óptimo, ya que el paralelo interno no sabrá acerca de sus hermanos y, por lo tanto, puede generar más en el servidor1 que en el servidor2. Una forma de evitarlo es -j1 en el paralelo externo, pero eso no será óptimo si el interno solo tiene suficientes bloques para el primer servidor. En otras palabras: para equilibrar perfectamente tu carga de trabajo, es posible que tengas que modificar un poco esto, tal vez incluso usar --load 100% o similar.
--- editar: lidiar con fallas ---
Si el process_pipe
resultado es un error, entonces debería volver a intentar el comando 2 veces más:
parallel --retries 3 --eta "cat {} | parallel --pipe -S server1,server2 'cat | process_pipe' > {}.out" ::: bigfiles*