Cos’è la concorrenza
Se esegui in sequenza più operazioni indipendenti (chiamate ad API esterne, aggregazioni DB, ecc.), il tempo totale è la somma di ciascuna. Eseguendole in parallelo il tempo totale si riduce al tempo dell’operazione più lenta. La facadeConcurrency di Laravel realizza questo con un’API semplice.
La facade
Concurrency è stata introdotta in Laravel 11 ed è disponibile anche in Laravel 13. Il driver predefinito usa processi PHP figli e non richiede pacchetti aggiuntivi.Come funziona
La facadeConcurrency serializza le closure passate, le invia a un comando Artisan nascosto e le esegue come processi PHP separati.
Al termine i valori di ritorno vengono serializzati e restituiti al processo genitore.
Sono disponibili tre driver:
Uso di base
Concurrency::run()
Passa arun() un array di closure: verranno eseguite in parallelo.
Ottieni i risultati come array nello stesso ordine delle closure.
Scegliere il driver
Condriver() specifichi un driver.
default.
Driver fork
fork è più veloce di process ma disponibile solo in CLI (Artisan, queue worker).
Non funziona nelle richieste web.
Prima installa spatie/fork.
Senza risultati: Concurrency::defer()
Se non ti interessa il risultato e vuoi eseguire dopo l’invio della risposta HTTP, usadefer().
Esempio pratico: chiamare più API in parallelo
Dashboard di e-commerce che consulta tre API (inventario, vendite, spedizioni).Sequenziale (prima)
Parallela (dopo)
Aggregazioni DB in parallelo
Propagazione automatica del Context
In Laravel 13.31 (#61419) il driverprocess ha iniziato a propagare automaticamente il Context corrente ai processi figli.
In precedenza, i valori impostati con Context::add() non venivano ereditati dai processi figli avviati con Concurrency::run() o Concurrency::defer(), e il context stampato nei log poteva risultare incoerente fra processo padre e figlio.
Dopo la correzione, internamente viene usato lo stesso meccanismo di trasferimento del contesto ai job in coda.
- Subito prima di avviare il processo figlio, il risultato di
Context::dehydrate()viene serializzato in JSON e passato come variabile d’ambiente__LARAVEL_CONTEXT - Quando il processo figlio (il comando Artisan nascosto
invoke-serialized-closure) parte, legge__LARAVEL_CONTEXTe chiamahydrate()sul repositoryContext
Il driver
fork usa la fork() a livello di sistema operativo fornita da spatie/fork, quindi il processo figlio viene avviato copiando così com’è lo spazio di memoria del processo padre.
Per questo il contesto era già naturalmente condiviso e questa correzione riguarda principalmente il driver process (quello che avvia un processo separato).Nei test
Usasync per esecuzione sequenziale, evitando l’overhead dei processi.
.env.testing:
Note
Limitazioni delle closure
Limitazioni delle closure
Le closure vengono serializzate. Non catturare oggetti non serializzabili (connessioni DB, file handle) da fuori: costruiscili dentro la closure.
Overhead di process
Overhead di process
process ha un costo di avvio dei figli: per operazioni molto brevi (< pochi ms) potresti non guadagnare. Utile per operazioni > 100ms.Limitazioni di fork
Limitazioni di fork
Non funziona in FPM/Apache, solo in Artisan e worker.
Eccezioni
Eccezioni
Se in parallelo viene sollevata un’eccezione,
run() la rilancia. Per continuare, gestiscila dentro ciascuna closure con try/catch.Prossimi passi
Code e job
Impara code e job per l’esecuzione asincrona in background.