Um achado unix melhor com processamento paralelo?

43

O find(1)utilitário unix é muito útil, permitindo-me executar uma ação em muitos arquivos que correspondem a determinadas especificações, por exemplo

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

O acima pode executar um script ou ferramenta em cada arquivo XML em um diretório específico.

Digamos que meu script / programa consome muito tempo de CPU e eu tenho 8 processadores. Seria bom processar até 8 arquivos por vez.

O GNU make permite o processamento paralelo de trabalhos com o -jsinalizador, mas findnão parece ter essa funcionalidade. Existe um método genérico alternativo de agendamento de tarefas para abordar isso?

PP.
fonte

Respostas:

65

xargscom a -Popção (número de processos). Digamos que eu quisesse compactar todos os arquivos de log em um diretório em uma máquina com 4 CPUs:

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

Você também pode dizer -n <number>o número máximo de unidades de trabalho por processo. Digamos que eu tivesse 2500 arquivos e eu disse:

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

Isso iniciaria 4 bzip2processos, cada um com 500 arquivos e, quando o primeiro terminasse, outro seria iniciado para os últimos 500 arquivos.

Não sei por que a resposta anterior usa xargs e make , você tem dois mecanismos paralelos lá!

Gaius
fonte
7
Com o find / xargs, tenha cuidado: encontre padrões para novas linhas como delimitadores de saída, mas xargs assume como padrão qualquer espaço em branco como delimitadores de entrada. Use -0 em ambos para garantir a segurança ou alterne para o GNU paralelo, cujo padrão é novas linhas como delimitadores de entrada (correspondendo à saída da busca).
ephemient 23/10/10
1
Uau, incrível! Acabei de verificar, e é verdade, o xargs tem uma -Popção!
PP.
Cuidado ao usar o xargs -P- ele tem um bug nunca corrigido de iludir a saída (ao contrário parallel) sempre que 2 threads produzem saída no mesmo momento exato ...
Vlad
34

O paralelo GNU também pode ajudar.

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

Observe que, sem o -j8argumento, o parallelpadrão é o número de núcleos em sua máquina :-)

efémero
fonte
6

Não há necessidade de "consertar" find- use- makese para lidar com o paralelismo.

Faça com que seu processo crie um arquivo de log ou outro arquivo de saída e use um Makefile como este:

.SUFFIXES:  .xml .out

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

e invocado assim:

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

Melhor ainda, se você garantir que o arquivo de saída seja criado apenas após a conclusão bem-sucedida do processo Java, poderá aproveitar makeo manuseio de dependências para garantir que da próxima vez apenas arquivos não processados ​​sejam executados.

Alnitak
fonte
1
Espero que não haja espaços ou outros caracteres "interessantes" nesses nomes de arquivos; Make não lida com isso de maneira muito elegante.
ephemient 23/10/10
Excelente ideia! Nunca pensei em usar makefiles como este.
Oscfri # 30/17
3

O Find tem uma opção paralela que você pode usar diretamente usando o símbolo "+"; não é necessário xargs. Combinando-o com o grep, ele pode rasgar sua árvore rapidamente, procurando correspondências. por exemplo, se estou procurando todos os arquivos no meu diretório de fontes que contêm a string 'foo', posso chamar
find sources -type f -exec grep -H foo {} +

Mark Evans
fonte
12
Lendo o manual de localização, você pode ver que a -exec command +sintaxe não a executa paralelamente, mas "agrupa" muitos arquivos e executa o comando com vários arquivos como argumentos ao mesmo tempo. Acontece que o grep pode examinar seus objetivos em paralelo.
Gyscos 21/03