
# Rinnakkaiset työprosessit

Greph jakaa teksti- ja AST-skannaukset työprosessijonolle, kun työn määrä on riittävän suuri kattamaan lisäkustannukset. Jono perustuu `pcntl_fork()`-toimintoon ja siirtyy prosessin sisäiseen suoritukseen, kun `ext-pcntl` ei ole käytettävissä (Windows, eräät PaaS-ympäristöt ja rajoitetut palvelinympäristöt).

## Rinnakkaisten skannausten käyttöönotto

Aseta `-j N` kohteessa CLI tai `jobs: N` asianmukaisessa asetuskohteessa:

```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),
);
```

## Milloin rinnakkaisuus käynnistyy

Greph ei suorita rinnakkaistamista ehdoitta. N prosessin käynnistäminen ja niiden tulosten välittäminen putkien kautta aiheuttavat lisäkustannuksia. Pienillä tiedostolistoilla nämä kustannukset ovat suurempia kuin itse haun. Siksi julkisivukerros laskee kynnysarvon tehtävien määrän, hakutilan ja hakumallin rakenteen perusteella. Vain kynnysarvon ylittävät tiedostolistat jaetaan työprosessijonolle.

Nykyiset heuristiikat (kohteessa `Greph\Greph::shouldUseTextWorkers` ja siihen liittyvissä tiedostoissa):

- Yhden työn ajot (`-j 1`) suoritetaan aina prosessin sisällä.
- Tavalliset tekstiskannaukset vaativat noin `jobs * 2_000` tiedostoa ennen työprosessijonon käyttöönottoa.
- Osumamäärän, osumia sisältävien tiedostojen ja ilman osumia olevien tiedostojen tilat laskevat kynnyksen noin `jobs * 750` tiedostoon, sillä tiedostokohtainen työ on kevyempää.
- Lyhyiden, tunnisteen muotoisten kiinteän merkkijonon hakumallien kynnys nousee noin `jobs * 4_000` tiedostoon, sillä kirjaimellisten merkkijonojen nopea hakupolku on jo niin tehokas, ettei rinnakkaistamisesta yleensä ole hyötyä.
- AST-haku ja AST:n uudelleenkirjoitus käyttävät kynnystä `jobs * 750`.

Nämä luvut ovat heuristisia arvioita, eivät lupauksia. Ne perustuvat aineistoon WordPress ja niitä voidaan muuttaa.

## Jonon toiminta

`Greph\Parallel\WorkSplitter` jakaa tiedostolistan N osaan. `Greph\Parallel\WorkerPool` käynnistää kunkin osan käsittelyyn yhden työprosessin. Kukin prosessi suorittaa saman sulkeuman omalle osalleen, ja `Greph\Parallel\ResultCollector` lukee sarjoitetut tulokset takaisin kunkin työprosessin Unix-socketparin kautta. Pääprosessi odottaa kaikkien työprosessien valmistumista, yhdistää tulokset ja järjestää ne uudelleen, jotta tulosteiden järjestys pysyy samana työn jakotavasta riippumatta.

Tekstitilassa työprosessijono käyttää mukautettua siirtoformaattia (`Greph\Text\TextResultCodec`), joka pitää sarjoitetun tietosisällön pienenä. AST-tila käyttää kohteen PHP vakio-`serialize()`-muotoa.

## Kun pcntl ei ole käytettävissä

Jos kohdetta `pcntl_fork` ei voi kutsua (Windows, kovennetut PHP-koontiversiot), jono siirtyy huomaamatta suorittamaan jokaisen osan prosessin sisällä. Tulos on sama kuin kohteessa `-j 1`. Greph ei aiheuta virhettä, vaan suorittaa työn yksisäikeisesti.

Voit havaita tämän ajonaikaisesti tarkistamalla kohteen `function_exists('pcntl_fork')`.

## Säätöohjeita

- Aloita asettamalla `-j` puoleen fyysisten suoritinydintesi määrästä ja nosta arvoa, kunnes suorituskyky ei enää parane.
- Pienissä tietovarastoissa pelkkään kirjaimellisen kiinteän merkkijonon hakuun yksi prosessi on yleensä nopeampi kuin mikään rinnakkainen kokoonpano.
- Julkaistuissa suorituskykytesteissä ei mitata rinnakkaista AST-hakua tai uudelleenkirjoitusta. Mittaa suorituskyky omalla hakemistopuullasi ennen työprosessien määrän valitsemista.
- Kohteen README rivit osiossa ”Scan Mode: Parallel Text” (`1`, `2` ja `4` työprosessia aineistolla WordPress) eivät mittaa työprosessijonoa: niissä haetaan lyhyttä kirjaimellista mallia `function`, jonka kynnysarvo `jobs * 4_000` tiedostoa ylittää aineiston koon. Siksi jokainen rivi suoritetaan prosessin sisällä ([#8](https://github.com/inline0/greph/issues/8)).

## Rajoitukset

- Nykyinen jono ei tue töiden dynaamista uudelleenjakoa. Jos yksi osa on muita huomattavasti raskaampi, jono odottaa hitaimman työprosessin valmistumista.
- Työprosessien tulokset tallennetaan puskuriin, kunnes kaikki prosessit ovat valmistuneet. Pitkään kestävän skannauksen tulosteiden virtauttamista (kuten `rg --json` virtauttaa tapahtumia) ei tueta rinnakkaistilassa.
- Pääprosessi järjestää tulokset uudelleen yhdistämisen jälkeen, joten työprosessijono ei vähennä huippumuistin käyttöä yhden prosessin skannaukseen verrattuna.

Nämä rajoitukset sopivat työkuormiin, joihin Greph on tarkoitettu (vuorovaikutteinen koodihaku, agenttien toistuvat työvaiheet ja CI-ajot tilannevedoksille). Niitä tarkastellaan uudelleen, jos profilointi osoittaa niiden olevan pullonkaula todellisilla aineistoilla.
