Как запустить многопоточный grep в терминале?

38

У меня есть папка с 250+ файлами по 2 ГБ каждый. Мне нужно найти строку / шаблон в этих файлах и вывести результат в outputфайл. Я знаю, что могу выполнить следующую команду, но она слишком медленная !!

grep mypattern * > output

Я хочу ускорить это. Будучи программистом на Java, я знаю, что многопоточность может быть использована для ускорения процесса. Я застрял на том, как начать grepв «многопоточном режиме» и записать вывод в один outputфайл.

Абхишек
источник
См. Также unix.stackexchange.com/q/131535
Стефан
1
Конечно, поиск большой коллекции файлов - классический пример проблемы, связанной с вводом-выводом. Следовательно, использование нескольких потоков не поможет.
Джонатан Хартли

Ответы:

31

Для этого есть два простых решения. В основном, используя xargsили parallel.

XARGS подход:

Вы можете использовать xargsс findследующим:

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

Где вы замените number_of_processesмаксимальное количество процессов, которые вы хотите запустить. Однако это не гарантирует значительную производительность в случае, если ваша производительность ограничена вводом / выводом. В этом случае вы можете попытаться запустить больше процессов, чтобы компенсировать потерянное время ожидания ввода-вывода.

Кроме того, с помощью поиска можно указать более сложные параметры, а не только шаблоны файлов, такие как время модификации и т. Д.

Одна возможная проблема с этим подходом, как объяснено комментариями Стефана, если файлов мало, xargsможет не запустить достаточно много процессов для них. Одним из решений будет использование -nопции для xargsуказания количества аргументов, которые он должен принимать из канала за раз. Установка -n1заставит xargsначать новый процесс для каждого отдельного файла. Это может быть желательным поведением, если файлы очень велики (как в случае с этим вопросом) и существует относительно небольшое количество файлов. Однако если сами файлы небольшие, накладные расходы на запуск нового процесса могут подорвать преимущество параллелизма, и в этом случае большее -nзначение будет лучше. Таким образом, -nопция может быть точно настроена в соответствии с размерами и количеством файлов.

Параллельный подход:

Другой способ сделать это - использовать инструмент Ole Tange GNU Parallel parallel(доступен здесь ). Это обеспечивает больший контроль над параллелизмом и даже может быть распределен по нескольким хостам (было бы полезно, например, если ваш каталог используется совместно). Простейший синтаксис с использованием параллельного будет:

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

где опция -j+1указывает параллельно запускать один процесс сверх количества ядер на вашем компьютере (это может быть полезно для задач с ограниченным вводом / выводом, вы можете даже попытаться увеличить их количество).

Параллель также имеет преимущество перед xargsфактическим сохранением порядка вывода из каждого процесса и генерацией непрерывного вывода. Например, xargsесли, если процесс 1 генерирует строку, скажем p1L1, процесс 2 генерирует строку p2L1, процесс 1 генерирует другую строку p1L2, вывод будет:

p1L1
p2L1
p1L2

тогда как с parallelвыводом должно быть:

p1L1
p1L2
p2L1

Это обычно более полезно, чем xargsвывод.

Bichoy
источник
1
Возможно, вы захотите использовать -nв сочетании с -P. Иначе, xargsможет не закончиться порождением нескольких процессов, если есть два файла.
Стефан Шазелас
1
Ну, -n1 будет начинаться по одному grepна файл. Если файлы не очень большие и их очень мало, вы, вероятно, захотите увеличить их немного, потратив время на запуск и остановку процессов grep вместо поиска в файлах.
Стефан Шазелас
9

Существует по крайней мере два способа ускорения работы процессора с помощью grep:

  • Если вы ищете фиксированную строку, а не регулярное выражение, укажите -Fфлаг;

  • Если ваш шаблон только для ASCII, используйте 8-битный языковой стандарт вместо UTF-8, например LC_ALL=C grep ....

Это не поможет, если ваш жесткий диск является узким местом; в этом случае, вероятно, распараллеливание тоже не поможет.

Эгмонт
источник
1
Только что в man grep«Прямом вызове указано, что egrep или fgrep устарели, но он позволяет историческим приложениям, которые полагаются на них, работать без изменений». Не уверен, что это действительно имеет значение, но это то же самое, чтоgrep -F
iyrin
1
Также, когда вы говорите «скорее, чем шаблон», вы имеете в виду регулярное выражение?
Айрин
В поиске «только ASCII» используется значительно меньше процессорного времени. Но вы должны прочитать предостережения, упомянутые в комментариях на stackoverflow.com/a/11777835/198219
famzah
3

Если проблема не связана с вводом / выводом, вы можете использовать инструмент, оптимизированный для многоядерной обработки.

Возможно, вы захотите взглянуть на sift ( http://sift-tool.org , заявление об отказе: я автор этого инструмента) или поисковик серебра ( https://github.com/ggreer/the_silver_searcher ).

Серебряный искатель имеет ограничение размера файла 2 ГБ, если вы используете шаблон регулярных выражений, а не поиск по строчкам.

Svent
источник
Конечно, поиск по группе файлов - это классический пример проблемы, связанной с IO?
Джонатан Хартли