¿Un mejor hallazgo de Unix con procesamiento paralelo?

43

La find(1)utilidad Unix es muy útil, ya que me permite realizar una acción en muchos archivos que coinciden con ciertas especificaciones, p. Ej.

find /dump -type f -name '*.xml' -exec java -jar ProcessFile.jar {} \;

Lo anterior podría ejecutar un script o herramienta sobre cada archivo XML en un directorio particular.

Digamos que mi script / programa requiere mucho tiempo de CPU y tengo 8 procesadores. Sería bueno procesar hasta 8 archivos a la vez.

GNU make permite el procesamiento de trabajos paralelos con el -jindicador, pero findno parece tener dicha funcionalidad. ¿Existe un método genérico alternativo de programación de trabajo para abordar esto?

PÁGINAS.
fuente

Respuestas:

65

xargscon la -Popción (número de procesos). Digamos que quería comprimir todos los archivos de registro en un directorio en una máquina de 4 CPU:

find . -name '*.log' -mtime +3 -print0 | xargs -0 -P 4 bzip2

También puede decir -n <number>la cantidad máxima de unidades de trabajo por proceso. Digamos que tenía 2500 archivos y dije:

find . -name '*.log' -mtime +3 -print0 | xargs -0 -n 500 -P 4 bzip2

Esto iniciaría 4 bzip2procesos, cada uno de los cuales con 500 archivos, y luego, cuando el primero terminara, se iniciaría otro para los últimos 500 archivos.

¡No estoy seguro de por qué usa la respuesta anterior xargs y make tienes dos motores paralelos allí!

Gayo
fuente
77
Con find / xargs, tenga cuidado: busque valores predeterminados para las nuevas líneas como delimitadores de salida, pero xargs tiene como valor predeterminado cualquier espacio en blanco como delimitadores de entrada. Use -0 en ambos para estar seguro, o cambie a GNU en paralelo, que por defecto es de nueva línea como delimitador de entrada (coincidencia de salida de búsqueda).
Ephemient
1
¡Fantástico! Acabo de comprobar, y es cierto, ¡xargs tiene una -Popción!
PP.
Tenga cuidado con el uso de xargs -P: tiene un error nunca corregido de desviar la salida (a diferencia parallel) cada vez que 2 hilos producen salida en el mismo momento exacto ...
Vlad
34

GNU paralela también puede ayudar.

find /dump -type f -name '*.xml' | parallel -j8 java -jar ProcessFile.jar {}

Tenga en cuenta que sin el -j8argumento, parallelel número predeterminado de núcleos en su máquina :-)

efímero
fuente
6

No es necesario "arreglar" find: hacer uso de makesí mismo para manejar el paralelismo.

Haga que su proceso cree un archivo de registro o algún otro archivo de salida, y luego use un Makefile como este:

.SUFFIXES:  .xml .out

.xml.out:
        java -jar ProcessFile.jar $< 1> $@

e invocado así:

find /dump -type f -name '*.xml' | sed -e 's/\.xml$/.out/' | xargs make -j8

Mejor aún, si se asegura de que el archivo de salida solo se crea al completar con éxito el proceso de Java, puede aprovechar makeel manejo de dependencias para garantizar que la próxima vez solo se realicen los archivos no procesados.

Alnitak
fuente
1
Esperemos que no haya espacios u otros caracteres "interesantes" en esos nombres de archivo; Make no los maneja con mucha elegancia.
Ephemient
¡Excelente idea! Nunca pensé en usar makefiles como este.
oscfri
3

Buscar tiene una opción paralela que puede usar directamente usando el símbolo "+"; No se requieren xargs. Combinándolo con grep, puede atravesar su árbol rápidamente buscando coincidencias. por ejemplo, si estoy buscando todos los archivos en mi directorio de fuentes que contienen la cadena 'foo', puedo invocar
find sources -type f -exec grep -H foo {} +

Mark Evans
fuente
12
Al leer el manual de búsqueda, puede ver que la -exec command +sintaxis no se ejecuta en paralelo, sino que "agrupa" muchos archivos y ejecuta el comando con varios archivos como argumentos al mismo tiempo. Sucede que grep puede mirar a través de sus objetivos en paralelo.
Gyscos