Lucrători paraleli
Greph distribuie scanările text și AST într-un grup de procese de lucru atunci când volumul justifică costul suplimentar. Grupul se bazează pe pcntl_fork() și revine la execuția în procesul curent când ext-pcntl nu este disponibil (Windows, unele medii PaaS, găzduire cu restricții).
Activarea scanărilor paralele
Setați -j N pentru CLI sau jobs: N în obiectul de opțiuni relevant:
./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),
);
Când începe execuția în paralel
Greph nu rulează întotdeauna în paralel. Pornirea a N procese și schimbul rezultatelor prin pipe-uri implică un cost suplimentar, iar pentru liste mici de fișiere acesta depășește costul căutării. În schimb, fațada calculează un prag în funcție de numărul de sarcini, modul de căutare și forma modelului. Doar listele de fișiere care depășesc pragul sunt distribuite grupului de procese de lucru.
euristicile actuale (din Greph\Greph::shouldUseTextWorkers și instrumentele conexe):
- Rulările cu o singură sarcină (
-j 1) se execută întotdeauna în procesul curent. - Scanările text implicite necesită aproximativ
jobs * 2_000fișiere înainte ca grupul să fie activat. - Modurile de numărare, fișiere cu potriviri și fișiere fără potriviri reduc pragul la aproximativ
jobs * 750, deoarece operația per fișier este mai ieftină. - Modelele scurte cu șir fix, de forma identificatorilor, măresc pragul la aproximativ
jobs * 4_000, deoarece calea rapidă literală este deja atât de ieftină încât pornirea proceselor rareori merită. - Căutarea și rescrierea AST folosesc pragul
jobs * 750.
Aceste valori sunt euristici, nu promisiuni. Sunt ajustate pe baza corpusului de testare WordPress și pot fi revizuite.
Cum funcționează grupul de procese
Greph\Parallel\WorkSplitter distribuie lista de fișiere în N segmente. Greph\Parallel\WorkerPool pornește câte un proces de lucru pentru fiecare segment; fiecare proces rulează aceeași funcție pe porțiunea alocată, iar Greph\Parallel\ResultCollector citește rezultatele serializate prin câte o pereche de socket-uri Unix pentru fiecare proces. Procesul părinte așteaptă terminarea tuturor proceselor, apoi îmbină și sortează din nou rezultatele, astfel încât ordinea ieșirii să rămână stabilă indiferent de împărțirea sarcinii.
Pentru modul text, grupul de procese folosește un codec personalizat pentru transmiterea datelor (Greph\Text\TextResultCodec), pentru a păstra compactă încărcătura serializată. Modul AST folosește PHP serialize() standard.
Când pcntl nu este disponibil
Dacă pcntl_fork nu poate fi apelat (Windows, compilări PHP securizate), grupul revine automat la execuția fiecărui segment în procesul curent. Rezultatul este același ca pentru -j 1. Greph nu generează o eroare; rulează pur și simplu pe un singur fir de execuție.
Puteți detecta acest lucru în timpul execuției verificând function_exists('pcntl_fork').
Recomandări de ajustare
- Începeți cu
-jsetat la jumătate din numărul de nuclee fizice și măriți valoarea până când nu mai observați îmbunătățiri. - Pentru căutările exclusiv literale cu șir fix în depozite mici, un singur proces este de obicei mai rapid decât orice configurație paralelă.
- Niciun test de performanță publicat nu măsoară căutarea sau rescrierea AST în paralel. Măsurați pe propriul arbore înainte de a stabili numărul de sarcini.
- Rândurile „Modul de scanare: text paralel” din README (
1,2și4procese de lucru pe corpusul WordPress) nu măsoară grupul de procese: caută literalul scurtfunction, al cărui prag dejobs * 4_000fișiere depășește dimensiunea corpusului, așadar fiecare rând rulează în procesul curent (#8).
Limitări
- Grupul actual nu acceptă distribuirea dinamică a sarcinilor. Dacă un segment este mult mai greu decât celelalte, grupul așteaptă cel mai lent proces de lucru.
- Rezultatele proceselor de lucru sunt păstrate în memorie până când toate se termină. Modul paralel nu acceptă transmiterea treptată a ieșirii unei scanări de lungă durată, așa cum
rg --jsontransmite evenimente. - Procesul părinte sortează din nou rezultatele după îmbinare, astfel încât grupul de procese nu reduce consumul maxim de memorie față de o scanare cu un singur proces.
Aceste limitări sunt acceptabile pentru sarcinile vizate de Greph (căutare interactivă în cod, bucle de agent, joburi CI pe instantanee). Le vom reevalua dacă profilarea arată că devin un blocaj în corpusuri reale.