Como iniciar o grep multi-threaded no terminal?

38

Eu tenho uma pasta que tem mais de 250 arquivos de 2 GB cada. Preciso procurar uma string / padrão nesses arquivos e gerar o resultado em um outputarquivo. Eu sei que posso executar o seguinte comando, mas é muito lento!

grep mypattern * > output

Eu quero acelerar isso. Sendo um programador em Java, sei que o multi-threading pode ser usado para acelerar o processo. Estou preso em como iniciar grepno "modo multiencadeado" e gravar a saída em um único outputarquivo.

Abhishek
fonte
Veja também unix.stackexchange.com/q/131535
Stéphane Chazelas
E unix.stackexchange.com/q/85789
Stéphane Chazelas
1
Certamente, pesquisar uma grande coleção de arquivos é o exemplo clássico de um problema vinculado às E / S. Portanto, o uso de vários threads não ajudará.
Jonathan Hartley

Respostas:

31

Existem duas soluções fáceis para isso. Basicamente, usando xargsou parallel.

Abordagem xargs:

Você pode usar xargscom findo seguinte:

find . -type f -print0  | xargs -0 -P number_of_processes grep mypattern > output

Onde você substituirá number_of_processespelo número máximo de processos que deseja iniciar. No entanto, isso não garante que você tenha um desempenho significativo caso seu desempenho seja limitado de E / S. Nesse caso, você pode tentar iniciar mais processos para compensar o tempo perdido na espera de E / S.

Além disso, com a inclusão de find, você pode especificar opções mais avançadas em vez de apenas padrões de arquivo, como tempo de modificação, etc ...

Um possível problema com essa abordagem, conforme explicado pelos comentários de Stéphane, se houver poucos arquivos, xargspode não iniciar muitos processos para eles. Uma solução será usar a -nopção para xargsespecificar quantos argumentos devem ser retirados do canal por vez. A configuração -n1forçará o xargsinício de um novo processo para cada arquivo único. Esse pode ser um comportamento desejado se os arquivos forem muito grandes (como no caso desta pergunta) e houver um número relativamente pequeno de arquivos. No entanto, se os arquivos forem pequenos, a sobrecarga de iniciar um novo processo poderá prejudicar a vantagem do paralelismo, caso em que um -nvalor maior será melhor. Portanto, a -nopção pode ser ajustada de acordo com o tamanho e o número do arquivo.

Abordagem Paralela:

Outra maneira de fazer isso é usar a ferramenta Ole Tange GNU Parallel parallel, (disponível aqui ). Isso oferece maior controle de granulação fina sobre paralelismo e pode até ser distribuído por vários hosts (seria benéfico se seu diretório fosse compartilhado, por exemplo). A sintaxe mais simples usando paralelo será:

find . -type f | parallel -j+1 grep mypattern

onde a opção -j+1instrui paralelamente a iniciar um processo além do número de núcleos em sua máquina (isso pode ser útil para tarefas limitadas de E / S, você pode até tentar aumentar em número).

O paralelo também tem a vantagem xargsde realmente reter a ordem da saída de cada processo e gerar uma saída contígua. Por exemplo, com xargs, se o processo 1 gerar uma linha p1L1, digamos , o processo 2 gerar uma linha p2L1, o processo 1 gerar outra linha p1L2, a saída será:

p1L1
p2L1
p1L2

considerando que com parallela saída deve ser:

p1L1
p1L2
p2L1

Isso geralmente é mais útil que a xargssaída.

Bichoy
fonte
1
Você provavelmente gostaria de usar -nem combinação com -P. Caso contrário, xargspode não acabar gerando vários processos se houver dois poucos arquivos.
Stéphane Chazelas
1
Bem, -n1 iniciaria um greppor arquivo. A menos que os arquivos sejam muito grandes e existam muito poucos, você provavelmente aumentará um pouco, pois gastará seu tempo iniciando e parando os processos grep em vez de pesquisar nos arquivos.
Stéphane Chazelas
9

Existem pelo menos duas maneiras de acelerar o grep em termos de CPU:

  • Se você estiver procurando por uma sequência fixa em vez de uma expressão regular, especifique o -Fsinalizador;

  • Se o seu padrão for apenas ASCII, use um código de idioma de 8 bits em vez de UTF-8, por exemplo LC_ALL=C grep ....

Isso não ajudará se o seu disco rígido for o gargalo; nesse caso, provavelmente o paralelismo também não ajudará.

Egmont
fonte
1
Acabei de ver em man grep"A chamada direta como egrep ou fgrep está obsoleta, mas é fornecida para permitir que aplicativos históricos que dependem deles sejam executados sem modificação". Não tenho certeza disso importa realmente, mas é o mesmo quegrep -F
iyrin
1
Além disso, quando você diz "em vez de um padrão", está se referindo a uma expressão regular?
IRobin
A pesquisa "somente ASCII" usa muito menos CPU. Mas você precisa ler as advertências mencionadas nos comentários em stackoverflow.com/a/11777835/198219
famzah
3

Se o problema não estiver vinculado à E / S, você poderá usar uma ferramenta otimizada para processamento com vários núcleos.

Você pode dar uma olhada no sift ( http://sift-tool.org , aviso: eu sou o autor desta ferramenta) ou no pesquisador prateado ( https://github.com/ggreer/the_silver_searcher ).

o pesquisador prateado tem um limite de tamanho de arquivo de 2 GB se você usar um padrão de regex e não uma pesquisa de cadeia de espinha.

svent
fonte
Certamente pesquisar um monte de arquivos é um exemplo clássico de um problema vinculado a IO?
Jonathan Hartley