Jak uruchomić wielowątkowy grep w terminalu?

38

Mam folder zawierający ponad 250 plików o wielkości 2 GB każdy. Muszę wyszukać ciąg / wzorzec w tych plikach i wyświetlić wynik w outputpliku. Wiem, że mogę uruchomić następujące polecenie, ale jest ono zbyt wolne !!

grep mypattern * > output

Chcę to przyspieszyć. Jako programista w Javie wiem, że do przyspieszenia tego procesu można wykorzystać wielowątkowość. Utknąłem, jak zacząć grepw „trybie wielowątkowym” i zapisać dane wyjściowe w jednym outputpliku.

Abhishek
źródło
Zobacz także unix.stackexchange.com/q/131535
Stéphane Chazelas
I unix.stackexchange.com/q/85789
Stéphane Chazelas
1
Z pewnością przeszukiwanie dużej kolekcji plików jest klasycznym przykładem problemu związanego z IO. Dlatego używanie wielu wątków nie pomoże.
Jonathan Hartley

Odpowiedzi:

31

Są na to dwa proste rozwiązania. Zasadniczo za pomocą xargslub parallel.

Podejście xargs:

Można skorzystać xargsz findco następuje:

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

Gdzie zastąpisz number_of_processesmaksymalną liczbę procesów, które chcesz uruchomić. Nie gwarantuje to jednak znaczącej wydajności w przypadku ograniczonej wydajności we / wy. W takim przypadku możesz spróbować uruchomić więcej procesów w celu zrekompensowania straconego czasu oczekiwania na operacje we / wy.

Ponadto, dzięki włączeniu funkcji find, możesz określić bardziej zaawansowane opcje zamiast tylko wzorów plików, takich jak czas modyfikacji itp.

Jeden z możliwych problemów z tym podejściem, wyjaśniony w komentarzach Stéphane'a, jeśli plików jest niewiele, xargsmoże nie uruchomić dla nich wystarczająco wielu procesów. Jednym z rozwiązań będzie użycie -nopcji xargsdo określenia, ile argumentów ma pobierać z potoku na raz. Ustawienie -n1wymusi xargsrozpoczęcie nowego procesu dla każdego pojedynczego pliku. Może to być pożądane zachowanie, jeśli pliki są bardzo duże (jak w przypadku tego pytania) i istnieje stosunkowo niewielka liczba plików. Jeśli jednak same pliki są małe, narzut związany z uruchomieniem nowego procesu może podważyć przewagę równoległości, w którym to przypadku -nlepsza wartość będzie lepsza. W związku z tym -nopcja może zostać dokładnie dostosowana do rozmiaru i liczby plików.

Podejście równoległe:

Innym sposobem na to jest użycie narzędzia Ole Tange GNU Parallel parallel(dostępne tutaj ). Zapewnia to większą kontrolę drobnoziarnistości nad równoległością, a nawet może być rozdzielone na wiele hostów (byłoby to korzystne, jeśli na przykład katalog jest udostępniany). Najprostsza składnia przy użyciu równoległości będzie:

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

gdzie opcja -j+1nakazuje równolegle rozpoczęcie jednego procesu przekraczającego liczbę rdzeni na komputerze (może to być pomocne w przypadku ograniczonych zadań we / wy, możesz nawet spróbować zwiększyć liczbę).

Równolegle ma również tę zaletę, xargsże faktycznie zachowuje porządek wyjścia z każdego procesu i generuje ciągły wynik. Na przykład, xargsjeśli proces 1 generuje linię powiedzmy p1L1, proces 2 generuje linię p2L1, proces 1 generuje inną linię p1L2, wynikiem będzie:

p1L1
p2L1
p1L2

mając na uwadze, parallelże wynikiem powinno być:

p1L1
p1L2
p2L1

Jest to zwykle bardziej przydatne niż xargswyjście.

Bichoj
źródło
1
Prawdopodobnie chcesz używać -nw połączeniu z -P. W przeciwnym razie xargsmoże się nie powieść spawnowanie kilku procesów, jeśli jest kilka plików.
Stéphane Chazelas,
1
Cóż, -n1 uruchamia jeden grepna plik. Jeśli pliki nie są bardzo duże i jest ich bardzo mało, prawdopodobnie zechcesz to nieco zwiększyć, ponieważ spędzasz czas na uruchamianiu i zatrzymywaniu procesów grep zamiast przeszukiwania plików.
Stéphane Chazelas,
9

Istnieją co najmniej dwa sposoby przyspieszenia grep pod względem procesora:

  • Jeśli szukasz stałego ciągu zamiast wyrażenia regularnego, określ -Fflagę;

  • Jeśli twój wzorzec jest tylko ASCII, użyj 8-bitowych ustawień narodowych zamiast UTF-8, np LC_ALL=C grep ....

To nie pomoże, jeśli twój dysk twardy jest wąskim gardłem; w takim przypadku prawdopodobnie równoległość też nie pomoże.

egmont
źródło
1
Właśnie zobaczyłem w man grep„Bezpośrednie wywoływanie, ponieważ albo egrep, albo fgrep jest przestarzałe, ale jest zapewnione, aby umożliwić aplikacjom historycznym, które na nich polegają, działać niezmodyfikowane”. Nie jestem pewien, czy to naprawdę ważne, ale jest to to samo, cogrep -F
iyrin,
1
Czy kiedy mówisz „zamiast wzoru”, masz na myśli wyrażenie regularne?
iyrin
Wyszukiwanie „tylko ASCII” zużywa znacznie mniej procesora. Ale musisz przeczytać zastrzeżenia wymienione w komentarzach na stackoverflow.com/a/11777835/198219
famzah
3

Jeśli problem nie jest związany z operacjami we / wy, można użyć narzędzia zoptymalizowanego pod kątem przetwarzania wielordzeniowego.

Możesz rzucić okiem na sift ( http://sift-tool.org , wyłączenie odpowiedzialności: Jestem autorem tego narzędzia) lub srebrny wyszukiwarkę ( https://github.com/ggreer/the_silver_searcher ).

srebrny wyszukiwarka ma limit wielkości pliku 2 GB, jeśli używasz wzorca wyrażenia regularnego, a nie wyszukiwania ciągów znaków.

svent
źródło
Czy przeszukiwanie wielu plików jest klasycznym przykładem problemu związanego z IO?
Jonathan Hartley