Hoppa till innehåll

Parallella arbetare

Greph fördelar text- och AST-sökningar över en arbetarpool när arbetet är tillräckligt omfattande för att motivera omkostnaden. Poolen bygger på pcntl_fork() och går över till körning i samma process när ext-pcntl inte är tillgängligt (Windows, vissa PaaS-miljöer och begränsade värdmiljöer).

Aktivera parallella sökningar

Ange -j N på CLI eller jobs: N i det relevanta optionsobjektet:

Shell
./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
PHP
use Greph\Greph;
use Greph\Text\TextSearchOptions;

Greph::searchText(
    'function',
    'src',
    new TextSearchOptions(fixedString: true, jobs: 8),
);

När parallell körning aktiveras

Greph parallelliserar inte villkorslöst. Att förgrena N processer och skicka deras resultat fram och tillbaka via rör medför en kostnad, och för små fillistor överstiger den kostnaden själva sökningen. I stället beräknar fasaden en tröskel utifrån antalet jobb, sökläget och mönstrets form. Endast fillistor som överskrider tröskeln skickas till arbetarpoolen.

De aktuella heuristikerna (i Greph\Greph::shouldUseTextWorkers och närliggande kod):

  • Körningar med ett jobb (-j 1) körs alltid i samma process.
  • Standardsökningar i text kräver ungefär jobs * 2_000 filer innan poolen aktiveras.
  • Lägena för antal träffar, filer med träffar och filer utan träffar sänker tröskeln till ungefär jobs * 750 eftersom arbetet per fil är billigare.
  • Korta mönster med fast sträng som liknar identifierare höjer tröskeln till ungefär jobs * 4_000 eftersom den snabba vägen för bokstavliga strängar redan är så billig att förgrening sällan lönar sig.
  • AST-sökning och AST-omskrivning använder tröskeln jobs * 750.

Dessa tal är heuristiker, inte garantier. De är finjusterade mot benchmarkkorpusen WordPress och kan komma att ses över.

Så fungerar poolen

Greph\Parallel\WorkSplitter fördelar fillistan i N delar. Greph\Parallel\WorkerPool förgrenar en arbetarprocess per del. Varje arbetare kör samma closure på sin del, och Greph\Parallel\ResultCollector läser tillbaka de serialiserade resultaten via ett Unix-socketpar per arbetare. Den överordnade processen väntar på alla arbetare och sammanfogar sedan resultaten och sorterar dem igen, så att utdataordningen är stabil oavsett hur arbetet delades upp.

För textläget använder arbetarpoolen en anpassad codec på tråden (Greph\Text\TextResultCodec) för att hålla den serialiserade nyttolasten liten. AST-läget använder standardlösningen serialize() från PHP.

När pcntl inte är tillgängligt

Om pcntl_fork inte kan anropas (Windows, härdade byggen av PHP) går poolen sömlöst över till att köra varje del i samma process. Resultatet är detsamma som för -j 1. Greph ger inget fel utan körs bara med en tråd.

Du kan upptäcka detta vid körning genom att kontrollera function_exists('pcntl_fork').

Råd för finjustering

  • Börja med att ange -j till hälften av antalet fysiska kärnor och höj värdet tills förbättringarna uteblir.
  • För sökningar med enbart bokstavliga fasta strängar i små arkiv är en enda process oftast snabbare än alla parallella konfigurationer.
  • Inget publicerat prestandatest mäter parallell AST-sökning eller omskrivning. Mät på ditt eget träd innan du bestämmer antalet jobb.
  • Raderna ”Sökläge: parallell text” i README (1, 2 och 4 arbetare på korpusen WordPress) mäter inte poolen: de söker efter den korta bokstavliga strängen function, vars tröskel på jobs * 4_000 filer överstiger korpusens storlek, så varje rad körs i samma process (#8).

Begränsningar

  • Den aktuella poolen stöder inte arbetsstöld. Om en del är mycket tyngre än de andra väntar poolen på den långsammaste arbetaren.
  • Arbetarresultaten buffras tills alla arbetare är klara. Strömmande utdata från en långvarig sökning (som när rg --json strömmar händelser) stöds inte i parallellt läge.
  • Den överordnade processen sorterar om resultaten efter sammanslagningen, så arbetarpoolen minskar inte toppminnesanvändningen jämfört med en genomsökning i en enda process.

Dessa begränsningar är acceptabla för de arbetsbelastningar som Greph riktar sig till (interaktiv kodsökning, agentloopar och CI-jobb över ögonblicksbilder). De ses över om profilering visar att de är en flaskhals på verkliga korpusar.