
# 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:

```bash
./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](https://github.com/inline0/greph/issues/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.
