Wie starte ich Multi-Threaded Grep im Terminal?

38

Ich habe einen Ordner mit mehr als 250 Dateien mit jeweils 2 GB. Ich muss in diesen Dateien nach einer Zeichenfolge / einem Muster suchen und das Ergebnis in einer outputDatei ausgeben . Ich weiß, dass ich den folgenden Befehl ausführen kann, aber er ist zu langsam !!

grep mypattern * > output

Ich möchte es beschleunigen. Als Programmierer in Java weiß ich, dass Multithreading verwendet werden kann, um den Prozess zu beschleunigen. Ich bin nicht sicher, wie ich grepim "Multithread-Modus" starten und die Ausgabe in eine einzelne outputDatei schreiben soll .

Abhishek
quelle
Siehe auch unix.stackexchange.com/q/131535
Stéphane Chazelas
Und unix.stackexchange.com/q/85789
Stéphane Chazelas
1
Sicherlich ist das Durchsuchen einer großen Sammlung von Dateien das klassische Beispiel für ein Problem, das an E / A gebunden ist. Daher hilft es nicht, mehrere Threads zu verwenden.
Jonathan Hartley

Antworten:

31

Hierfür gibt es zwei einfache Lösungen. Grundsätzlich mit xargsoder parallel.

xargs Ansatz:

Sie können xargsmit findwie folgt verwenden:

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

Wobei Sie number_of_processesdurch die maximale Anzahl von Prozessen ersetzen, die Sie starten möchten. Es wird jedoch nicht garantiert, dass Sie eine signifikante Leistung erhalten, wenn Ihre Leistung auf E / A beschränkt ist. In diesem Fall können Sie versuchen, weitere Prozesse zu starten, um die Wartezeit auf E / A-Vorgänge zu kompensieren.

Außerdem können Sie mit find erweiterte Optionen angeben, anstatt nur Dateimuster wie Änderungszeit usw. anzugeben.

Ein mögliches Problem bei diesem Ansatz ist, wie in den Kommentaren von Stéphane erläutert, dass wenn nur wenige Dateien vorhanden sind, xargsmöglicherweise nicht genügend viele Prozesse für diese gestartet werden. Eine Lösung besteht darin, mit der -nOption für xargsanzugeben, wie viele Argumente gleichzeitig aus der Pipe entnommen werden sollen. Die Einstellung -n1erzwingt xargs, dass für jede einzelne Datei ein neuer Prozess gestartet wird. Dies kann ein gewünschtes Verhalten sein, wenn die Dateien sehr groß sind (wie im Fall dieser Frage) und eine relativ kleine Anzahl von Dateien vorhanden ist. Wenn die Dateien selbst klein sind, kann der Mehraufwand beim Starten eines neuen Prozesses den Vorteil der Parallelität beeinträchtigen. In diesem Fall ist ein höherer -nWert besser. Daher kann die -nOption je nach Dateigröße und Anzahl fein eingestellt werden.

Parallele Annäherung:

Eine andere Möglichkeit ist die Verwendung des Ole Tange GNU Parallel-Tools parallel( hier verfügbar ). Dies bietet eine genauere Kontrolle über die Parallelität und kann sogar auf mehrere Hosts verteilt werden (wäre von Vorteil, wenn Ihr Verzeichnis beispielsweise gemeinsam genutzt wird). Die einfachste parallele Syntax ist:

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

Wobei die Option -j+1parallel anweist, einen Prozess zu starten, der die Anzahl der Kerne auf Ihrem Computer überschreitet (Dies kann hilfreich sein, wenn die Anzahl der E / A-Aufgaben begrenzt ist. Möglicherweise versuchen Sie sogar, die Anzahl zu erhöhen).

Parallel hat auch den Vorteil, dass xargsdie Reihenfolge der Ausgabe von jedem Prozess beibehalten und eine zusammenhängende Ausgabe generiert wird. Beispiel: xargsWenn Prozess 1 eine Zeile generiert, z. B. p1L1Prozess 2 eine Zeile generiert p2L1, Prozess 1 eine weitere Zeile generiert, lautet p1L2die Ausgabe:

p1L1
p2L1
p1L2

während mit parallelder Ausgabe sollte sein:

p1L1
p1L2
p2L1

Dies ist normalerweise nützlicher als die xargsAusgabe.

Bichoy
quelle
1
Sie möchten wahrscheinlich -nin Kombination mit -P. Andernfalls können xargsmöglicherweise nicht mehrere Prozesse gestartet werden, wenn zwei wenige Dateien vorhanden sind.
Stéphane Chazelas
1
Nun, -n1 würde eins greppro Datei starten . Wenn die Dateien nicht sehr groß sind und es nur sehr wenige gibt, sollten Sie sie wahrscheinlich etwas vergrößern, da Sie Ihre Zeit damit verbringen, grep-Prozesse zu starten und anzuhalten, anstatt in Dateien zu suchen.
Stéphane Chazelas
9

Es gibt mindestens zwei Möglichkeiten, die Geschwindigkeit der CPU zu erhöhen:

  • Wenn Sie nach einer festen Zeichenfolge und nicht nach einem regulären Ausdruck suchen, geben Sie das -FFlag an.

  • Wenn Ihr Muster nur ASCII ist, verwenden Sie ein 8-Bit-Gebietsschema anstelle von UTF-8, z LC_ALL=C grep ....

Dies hilft jedoch nicht, wenn Ihre Festplatte der Engpass ist. In diesem Fall hilft wahrscheinlich auch das Parallelisieren nicht.

egmont
quelle
1
Nur in man grep"Direkter Aufruf als entweder egrep oder fgrep ist veraltet, wird aber bereitgestellt, damit historische Anwendungen, die darauf angewiesen sind, unverändert ausgeführt werden können." Ich grep -F
bin
1
Auch wenn Sie "eher als ein Muster" sagen, beziehen Sie sich auf einen regulären Ausdruck?
Iyrin
Die Suche "Nur ASCII" verbraucht massiv weniger CPU. Sie müssen jedoch die in den Kommentaren unter stackoverflow.com/a/11777835/198219
famzah,
3

Wenn das Problem nicht E / A-gebunden ist, können Sie ein Tool verwenden, das für die Mehrkernverarbeitung optimiert ist.

Vielleicht möchten Sie einen Blick auf sift ( http://sift-tool.org , Haftungsausschluss: Ich bin der Autor dieses Tools) oder den Silver Searcher ( https://github.com/ggreer/the_silver_searcher ) werfen .

Der Silver Searcher hat eine Dateigrößenbeschränkung von 2 GB, wenn Sie ein reguläres Muster und keine einfache Zeichenfolgensuche verwenden.

svent
quelle
Sicherlich ist das Durchsuchen einer Reihe von Dateien ein klassisches Beispiel für ein Problem, das an E / A gebunden ist?
Jonathan Hartley