
# Worker paralleli

Greph distribuisce le scansioni di testo e AST su un pool di worker quando il carico giustifica il sovraccarico. Il pool si basa su `pcntl_fork()` e passa all'esecuzione in-process se `ext-pcntl` non è disponibile (Windows, alcuni ambienti PaaS, hosting con restrizioni).

## Abilitare le scansioni parallele

Imposta `-j N` su CLI oppure `jobs: N` nell'oggetto delle opzioni pertinente:

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

## Quando si attiva l'esecuzione parallela

Greph non parallelizza incondizionatamente. Avviare N processi e scambiare i risultati tramite pipe ha un costo che, con elenchi di file ridotti, supera quello della ricerca stessa. Per questo la facade calcola una soglia in base al numero di job, alla modalità di ricerca e alla forma del pattern. Solo gli elenchi di file che superano la soglia vengono inviati al pool di worker.

Le euristiche attuali (in `Greph\Greph::shouldUseTextWorkers` e strumenti correlati):

- Le esecuzioni con un solo job (`-j 1`) avvengono sempre in-process.
- Le scansioni di testo predefinite richiedono circa `jobs * 2_000` file prima che si attivi il pool.
- Le modalità conteggio, file con corrispondenze e file senza corrispondenze abbassano la soglia a circa `jobs * 750`, perché il lavoro per file è meno costoso.
- I pattern a stringa fissa brevi, simili a identificatori, alzano la soglia a circa `jobs * 4_000`, perché il percorso rapido per i letterali è già così economico che avviare processi raramente conviene.
- La ricerca e la riscrittura AST usano la soglia `jobs * 750`.

Questi numeri sono euristiche, non garanzie. Sono tarati sul corpus di benchmark WordPress e possono essere rivisti.

## Funzionamento del pool

`Greph\Parallel\WorkSplitter` suddivide l'elenco dei file in N blocchi. `Greph\Parallel\WorkerPool` avvia un processo worker per ogni blocco; ogni worker esegue la stessa closure sulla propria porzione e `Greph\Parallel\ResultCollector` legge i risultati serializzati tramite una coppia di socket Unix per worker. Il processo padre attende tutti i worker, quindi unisce e riordina i risultati combinati, così l'ordine dell'output rimane stabile indipendentemente dalla suddivisione del lavoro.

Per la modalità testo, il pool di worker usa un codec personalizzato wire (`Greph\Text\TextResultCodec`) per mantenere compatto il payload serializzato. La modalità AST usa il formato standard `serialize()` di PHP.

## Quando pcntl non è disponibile

Se `pcntl_fork` non è richiamabile (Windows, build PHP rinforzate), il pool passa automaticamente all'esecuzione di ogni blocco in-process. Il risultato è lo stesso di `-j 1`. Greph non genera errori: esegue semplicemente un thread alla volta.

Puoi rilevarlo in fase di esecuzione controllando `function_exists('pcntl_fork')`.

## Consigli per la configurazione

- Inizia impostando `-j` a metà del numero di core fisici e aumentalo finché non smetti di vedere miglioramenti.
- Per ricerche a stringa fissa solo letterali in repository piccoli, un singolo processo è in genere più veloce di qualsiasi configurazione parallela.
- Nessun benchmark pubblicato misura la ricerca o la riscrittura AST parallele. Misura le prestazioni sul tuo albero prima di scegliere il numero di job.
- Le righe «Modalità di scansione: testo parallelo» del benchmark README (`1`, `2` e `4` worker sul corpus WordPress) non misurano il pool: cercano il breve letterale `function`, la cui soglia di `jobs * 4_000` file supera le dimensioni del corpus, quindi ogni riga viene eseguita in-process ([#8](https://github.com/inline0/greph/issues/8)).

## Limitazioni

- Il pool attuale non supporta il work-stealing. Se un blocco è molto più impegnativo degli altri, il pool attende il worker più lento.
- I risultati dei worker vengono memorizzati in buffer fino al termine di tutti i worker. In modalità parallela non è supportato lo streaming dell'output da una scansione di lunga durata (come fa `rg --json` con gli eventi).
- Dopo l'unione, il processo padre riordina i risultati: rispetto a una scansione con un solo processo, il pool di worker non riduce quindi il picco di memoria utilizzata.

Queste limitazioni sono accettabili per i carichi di lavoro a cui mira Greph (ricerca interattiva nel codice, cicli degli agenti, job CI su snapshot). Verranno rivalutate se la profilazione mostra che rappresentano un collo di bottiglia su corpus reali.
