Parallele Worker
Greph verteilt Text- und AST-Scans auf einen Worker-Pool, wenn der Arbeitsumfang den Mehraufwand rechtfertigt. Der Pool basiert auf pcntl_fork() und wechselt zur Ausführung im selben Prozess, wenn ext-pcntl nicht verfügbar ist (Windows, einige PaaS-Umgebungen, eingeschränktes Hosting).
Parallele Scans aktivieren
Setze -j N im CLI oder jobs: N im entsprechenden Optionsobjekt:
./vendor/bin/greph -F -j 8 "function" src
./vendor/bin/greph -p '$obj->$method($$$ARGS)' -j 4 src
./vendor/bin/rg --threads 8 -F "function" src
./vendor/bin/sg run --threads 8 --pattern '$obj->$method($$$ARGS)' src
use Greph\Greph;
use Greph\Text\TextSearchOptions;
Greph::searchText(
'function',
'src',
new TextSearchOptions(fixedString: true, jobs: 8),
);
Wann Parallelisierung einsetzt
Greph parallelisiert nicht bedingungslos. N Prozesse zu starten und ihre Ergebnisse über Pipes hin und her zu übertragen, verursacht Mehraufwand. Bei kleinen Dateilisten überwiegt dieser Aufwand die eigentliche Suche. Deshalb berechnet die Fassade anhand der Auftragszahl, des Suchmodus und der Musterform einen Schwellenwert. Nur Dateilisten oberhalb dieses Schwellenwerts werden an den Worker-Pool verteilt.
Die aktuellen Heuristiken (in Greph\Greph::shouldUseTextWorkers und verwandten Komponenten):
- Läufe mit einem einzelnen Job (
-j 1) werden immer im selben Prozess ausgeführt. - Bei standardmäßigen Textscans sind ungefähr
jobs * 2_000Dateien nötig, bevor der Pool aktiviert wird. - Modi für Trefferanzahl, Dateien mit Treffern und Dateien ohne Treffer senken den Schwellenwert auf ungefähr
jobs * 750, da die Arbeit pro Datei günstiger ist. - Bei kurzen Feststringmustern in Form von Bezeichnern steigt der Schwellenwert auf ungefähr
jobs * 4_000, da der schnelle Pfad für Literale bereits so günstig ist, dass sich das Aufteilen auf Prozesse selten lohnt. - AST-Suche und AST-Umschreibung verwenden den Schwellenwert
jobs * 750.
Diese Zahlen sind Richtwerte, keine Garantien. Sie sind auf das WordPress-Benchmark-Korpus abgestimmt und können überarbeitet werden.
Funktionsweise des Pools
Greph\Parallel\WorkSplitter verteilt die Dateiliste auf N Abschnitte. Greph\Parallel\WorkerPool startet einen Worker-Prozess pro Abschnitt. Jeder Worker führt dieselbe Closure für seinen Teil aus, und Greph\Parallel\ResultCollector liest die serialisierten Ergebnisse über ein Unix-Socket-Paar pro Worker zurück. Der übergeordnete Prozess wartet auf alle Worker und führt dann die Ergebnisse zusammen und sortiert sie erneut, damit die Ausgabereihenfolge unabhängig von der Aufteilung stabil bleibt.
Im Textmodus verwendet der Worker-Pool einen benutzerdefinierten Übertragungs-Codec (Greph\Text\TextResultCodec), um die serialisierte Nutzlast kompakt zu halten. Der AST-Modus verwendet PHPs standardmäßiges serialize().
Wenn pcntl nicht verfügbar ist
Wenn pcntl_fork nicht aufrufbar ist (Windows, gehärtete PHP-Builds), wechselt der Pool nahtlos zur Ausführung jedes Abschnitts im selben Prozess. Das Ergebnis entspricht -j 1. Greph gibt keinen Fehler aus, sondern läuft einfach ohne parallele Ausführung.
Du kannst das zur Laufzeit prüfen, indem du function_exists('pcntl_fork') überprüfst.
Hinweise zur Abstimmung
- Setze
-jzunächst auf die Hälfte deiner physischen Kerne und erhöhe den Wert, bis keine Verbesserungen mehr zu sehen sind. - Bei reinen Literalsuchen mit Feststrings in kleinen Repositories ist ein einzelner Prozess meist schneller als jede parallele Konfiguration.
- Kein veröffentlichter Benchmark misst parallele AST-Suche oder -Umschreibung. Miss die Leistung in deinem Verzeichnisbaum, bevor du eine Jobanzahl festlegst.
- Die Zeilen „Scan-Modus: Paralleler Text“ in der README (
1,2und4Worker auf dem WordPress-Korpus) messen den Pool nicht: Sie suchen nach dem kurzen Literalfunction, dessen Schwellenwert vonjobs * 4_000Dateien über der Korpusgröße liegt. Daher läuft jede Zeile im selben Prozess (#8).
Einschränkungen
- Der aktuelle Pool unterstützt kein Work-Stealing. Wenn ein Abschnitt deutlich mehr Arbeit verursacht als die anderen, muss der Pool auf den langsamsten Worker warten.
- Die Worker-Ergebnisse werden gepuffert, bis alle Worker fertig sind. Eine Streaming-Ausgabe während eines lang laufenden Scans (wie sie
rg --jsonfür Ereignisse bietet) wird im parallelen Modus nicht unterstützt. - Der übergeordnete Prozess sortiert die Ergebnisse nach dem Zusammenführen erneut. Daher verringert der Worker-Pool im Vergleich zu einem Scan in einem einzelnen Prozess nicht den maximalen Speicherbedarf.
Diese Einschränkungen sind für die von Greph abgedeckten Arbeitslasten akzeptabel (interaktive Codesuche, Agentenschleifen, CI-Aufträge mit Momentaufnahmen). Sie werden neu bewertet, wenn Profiling einen Engpass bei realen Korpora zeigt.