---
title: "Concurrency::run() in Laravel: esecuzione parallela di task I/O-bound senza code, worker o estensioni pcntl"
description: "Concurrency::run() di Laravel spawna processi PHP figli, non usa fibers. Parallelizza chiamate API e query indipendenti con un'API dichiarativa, ma con vincoli precisi."
canonical: "https://www.mauriziofonte.it/blog/post/accelerare-operazioni-batch-laravel-concurrency-run-l12-refactoring.html"
author: "Maurizio Fonte"
date: "2025-02-20T13:04:36+01:00"
modified: "2026-04-14T17:48:55+02:00"
section: "Laravel"
tags: ["Laravel", "Refactoring"]
license: "Riuso e citazione consentiti con attribuzione e link alla fonte"
---

[Laravel](https://www.mauriziofonte.it/blog/cat/laravel.html) [Refactoring](https://www.mauriziofonte.it/blog/cat/refactoring.html)

# [Concurrency::run() in Laravel: esecuzione parallela di task I/O-bound senza code, worker o estensioni pcntl](https://www.mauriziofonte.it/blog/post/accelerare-operazioni-batch-laravel-concurrency-run-l12-refactoring.html)

Giovedì 20 Febbraio 2025, alle 13:04 ![Concurrency::run() in Laravel: esecuzione parallela di task I/O-bound senza code, worker o estensioni pcntl](https://www.mauriziofonte.it/image/001400200-accelerare-operazioni-batch-laravel-concurrency-run-l12-refactoring.jpg)

In una piattaforma marketplace con migliaia di utenti attivi, un comando Artisan di sincronizzazione notturna chiamava 5 API esterne in sequenza per ogni ordine: verifica pagamento, aggiornamento inventario, calcolo spedizione, generazione fattura, notifica al fornitore. Con 200 ordini da processare e una latenza media di 800ms per chiamata API, il comando impiegava 13 minuti - 200 ordini × 5 chiamate × 0.8s. Le 5 chiamate per ogni ordine erano indipendenti tra loro, ma il codice le eseguiva una dopo l'altra perché PHP non offre concorrenza nativa senza estensioni. La [legge di Amdahl](https://en.wikipedia.org/wiki/Amdahl%2527s_law) formalizza il problema: se il 95% del tempo è speso in attesa di I/O parallelizzabile, il massimo speedup teorico con 5 task paralleli è 3.6× - da 13 minuti a meno di 4.

## Come funziona Concurrency::run() internamente?

[`Concurrency::run()`](https://laravel.com/docs/12.x/concurrency), introdotto in Laravel 11.23 e stabilizzato in Laravel 12, non usa fibers né thread. Il driver `process` (default) serializza ogni closure, la invia a un comando Artisan nascosto che la esegue in un processo PHP figlio separato, e restituisce il risultato serializzato al processo padre. Ogni processo figlio esegue il bootstrap completo dell'applicazione - service container, config, database connection - il che significa un overhead di 10-70ms per task.

Il driver `fork` usa [`spatie/fork`](https://github.com/spatie/fork) per creare processi tramite `pcntl_fork` - più veloce perché evita il bootstrap ripetuto, ma richiede l'estensione `pcntl` (non disponibile su Windows e in molti ambienti FPM) ed è utilizzabile solo in CLI. Il driver `sync` esegue tutto sequenzialmente - utile per i test.

L'API è dichiarativa: un array di closure in input, un array di risultati in output nello stesso ordine:

```php
use Illuminate\Support\Facades\Concurrency;
use Illuminate\Support\Facades\Http;

/* Sincronizzazione ordine: 5 API chiamate in parallelo invece che in sequenza */
$results = Concurrency::run([
    fn () => Http::shipping()->get("/rates/{$order->id}")->json(),
    fn () => Http::payments()->get("/verify/{$order->payment_id}")->json(),
    fn () => Http::inventory()->post('/reserve', ['items' => $order->items])->json(),
    fn () => Http::invoicing()->post('/generate', ['order' => $order->id])->json(),
    fn () => Http::suppliers()->post('/notify', ['order' => $order->id])->json(),
]);

[$rates, $payment, $inventory, $invoice, $supplier] = $results;
```

Le [macro HTTP](https://www.mauriziofonte.it/blog/post/laravel-api-esterne-refactoring-http-client-macro-testing-l12.html) (`Http::shipping()`, `Http::payments()`) centralizzano la configurazione di ogni servizio esterno. `Concurrency::run()` le esegue in parallelo - il tempo totale è quello della chiamata più lenta, non la somma di tutte e cinque.

`Concurrency::defer()` ha un caso d'uso diverso: esegue closure dopo che la risposta HTTP è stata inviata al client, in modalità fire-and-forget senza valore di ritorno. È utile per operazioni post-response come analytics, cache warming o cleanup.

## Quali sono i vincoli di Concurrency::run() che è essenziale conoscere?

Il primo vincolo è la serializzazione: le closure passate a `Concurrency::run()` devono essere serializzabili. Referenze a `$this`, connessioni database aperte, risorse file handle o oggetti non serializzabili causano un errore a runtime. Il pattern corretto è passare solo dati scalari o model ID nella closure, e risolvere le dipendenze all'interno:

```php
/* SBAGLIATO: $this non è serializzabile */
Concurrency::run([
    fn () => $this->service->process($order),
]);

/* CORRETTO: risolvere nel processo figlio */
$orderId = $order->id;
Concurrency::run([
    function () use ($orderId) {
        $service = app(OrderService::class);
        $order = Order::find($orderId);
        return $service->process($order);
    },
]);
```

Il secondo è l'isolamento dei processi: ogni task gira in un processo separato con la propria connessione database. Le transazioni del processo padre non sono visibili ai figli, e viceversa. Se un task scrive nel database, gli altri task non vedranno quella scrittura fino al commit. Per operazioni che richiedono consistenza transazionale, le [code Laravel](https://www.mauriziofonte.it/blog/post/modernizzare-job-coda-laravel-testing-queue-fake-interactions-l12.html) con job sequenziali sono l'alternativa corretta.

Il terzo è il costo del bootstrap: con il driver `process`, ogni task spawna un processo PHP che carica l'intera applicazione. Per 5 chiamate API da 800ms ciascuna, l'overhead di 50ms è trascurabile. Per 100 task da 10ms ciascuno, l'overhead (100 × 50ms = 5s) supera il tempo dei task stessi. La regola pratica: `Concurrency::run()` conviene quando il tempo di I/O per task è almeno 10× l'overhead di bootstrap.

Il quarto è la gestione dei fallimenti: se un task lancia un'eccezione, `Concurrency::run()` la propaga al processo padre. I risultati dei task completati con successo vanno persi. Per task dove i fallimenti parziali sono accettabili, ogni closure deve gestire le proprie eccezioni internamente e restituire un risultato che indichi successo o fallimento.

## Errori comuni nell'uso della concorrenza

Il primo errore è confondere concorrenza con code. `Concurrency::run()` è sincrono dal punto di vista del processo chiamante - blocca finché tutti i task non completano. Le [code Laravel](https://www.mauriziofonte.it/blog/post/modernizzare-job-coda-laravel-testing-queue-fake-interactions-l12.html) sono asincrone - il dispatch ritorna immediatamente e il job viene eseguito da un worker separato. Per operazioni I/O-bound dove serve il risultato immediatamente (aggregare dati da più API), usa Concurrency. Per operazioni fire-and-forget (inviare email, generare PDF), usa le code.

Il secondo è non limitare il numero di task concorrenti. 200 task in parallelo significano 200 processi PHP e 200 connessioni database. Un server con 4 CPU e un pool di 50 connessioni MySQL andrà in sofferenza. Il chunking è la strategia corretta: processare batch di 10-20 task alla volta con `collect($tasks)->chunk(15)->each(fn ($batch) => Concurrency::run($batch->all()))`.

Il terzo è usare Concurrency per task CPU-bound in ambiente web. Il driver `process` spawna processi che competono per la CPU con il web server - sotto carico, questo può degradare i tempi di risposta per tutti gli utenti. I task CPU-bound (elaborazione immagini, calcoli pesanti) appartengono alle [code con worker dedicati](https://www.mauriziofonte.it/blog/post/modernizzare-job-coda-laravel-testing-queue-fake-interactions-l12.html), non a `Concurrency::run()` in una request HTTP.

La concorrenza è uno strumento potente ma con un dominio di applicazione preciso: task I/O-bound indipendenti dove serve il risultato nel processo corrente. Fuori da questo dominio - task CPU-bound, operazioni con requisiti transazionali, fire-and-forget - le code e i job rimangono la scelta corretta. L'[ottimizzazione delle query Eloquent](https://www.mauriziofonte.it/blog/post/ottimizzazione-query-eloquent-laravel-performance-gestionali-ecommerce-pmi.html) e il [logging strategico](https://www.mauriziofonte.it/blog/post/logging-strategico-laravel-symfony-debugging-sicurezza-analisi-applicativi-pmi.html) delle metriche di esecuzione completano il quadro per applicativi ad alte prestazioni. Per conoscere il mio approccio all'ottimizzazione di applicativi Laravel, visita [la mia pagina professionale](https://www.mauriziofonte.it/pages/about). Se il tuo applicativo esegue operazioni batch sequenziali che potrebbero beneficiare della parallelizzazione, [contattami per una consulenza dedicata](https://www.mauriziofonte.it/pages/contattami) - partiamo dal profiling dei tempi di esecuzione e dall'identificazione dei bottleneck.

Dall'articolo al lavoro vero

Se il codice di cui parla questo articolo è il tuo

Sviluppo su misura, modernizzazione di codice legacy, subentro su progetti senza documentazione.

[Vedi tre interventi con i numeri](https://www.mauriziofonte.it/programmatore-php.html) Ultima modifica: Martedì 14 Aprile 2026, alle 17:48 [« Articolo precedenteTesting dei job in coda Laravel: da Queue::fake() a withFakeQueueInteractions() per validare retry, release e failure senza broker19 Febbraio 2025](https://www.mauriziofonte.it/blog/post/modernizzare-job-coda-laravel-testing-queue-fake-interactions-l12.html)[Articolo successivo »Validazione in Laravel 12: da closure inline a Rule Objects con ValidationRule per regole testabili, riutilizzabili e type-safe21 Febbraio 2025](https://www.mauriziofonte.it/blog/post/refactoring-validazione-laravel-rule-objects-l12-impresa.html)

### Articoli correlati a Concurrency::run() in Laravel: esecuzione parallela di task I/O-bound senza code, worker o estensioni pcntl

- [Refactoring delle integrazioni API esterne in Laravel: da chiamate Guzzle sparse a HTTP Client con Macro e testing deterministico](https://www.mauriziofonte.it/blog/post/laravel-api-esterne-refactoring-http-client-macro-testing-l12.html)

  L'HTTP Client di Laravel wrappa Guzzle aggiungendo macro riutilizzabili, retry con backoff esponenziale e Http::fake per testing deterministico. · 18 Febbraio 2025

  ![Refactoring delle integrazioni API esterne in Laravel: da chiamate Guzzle sparse a HTTP Client con Macro e testing deterministico](https://www.mauriziofonte.it/image/001380070-laravel-api-esterne-refactoring-http-client-macro-testing-l12.jpg)
- [PHP Fibers: concorrenza cooperativa per applicazioni Laravel ad alto carico](https://www.mauriziofonte.it/blog/post/php-fibers-concorrenza-cooperativa-laravel-alto-carico.html)

  Un'API Laravel che doveva fare 12 chiamate HTTP esterne per comporre una risposta impiegava 3,2 secondi in media. Con PHP Fibers e Octane ho · 12 Novembre 2025

  ![PHP Fibers: concorrenza cooperativa per applicazioni Laravel ad alto carico](https://www.mauriziofonte.it/image/002700070-php-fibers-concorrenza-cooperativa-laravel-alto-carico.jpg)
- [L'helper once() in Laravel 12: memoizzazione per-request con WeakMap al posto di proprietà statiche e cache forzata](https://www.mauriziofonte.it/blog/post/ottimizzare-calcoli-ripetuti-laravel-refactoring-helper-once-l12.html)

  L'helper once , introdotto in Laravel 11 PR 49744, Nuno Maduro , usa internamente una WeakMap di PHP 8.0 per cachare il risultato di una closure · 28 Febbraio 2025

  ![L'helper once() in Laravel 12: memoizzazione per-request con WeakMap al posto di proprietà statiche e cache forzata](https://www.mauriziofonte.it/image/001460070-ottimizzare-calcoli-ripetuti-laravel-refactoring-helper-once-l12.jpg)
- [Event discovery in Laravel 12: da EventServiceProvider a auto-discovery per listener disaccoppiati e testabili](https://www.mauriziofonte.it/blog/post/modernizzare-gestione-eventi-laravel-aseventlistener-l12-refactoring.html)

  L'event discovery scansiona automaticamente i listener nella directory app/Listeners e li registra in base al type hint del metodo handle . Introdotto · 26 Febbraio 2025

  ![Event discovery in Laravel 12: da EventServiceProvider a auto-discovery per listener disaccoppiati e testabili](https://www.mauriziofonte.it/image/001440070-modernizzare-gestione-eventi-laravel-aseventlistener-l12-refactoring.jpg)
- [Fat Controller in Laravel 12: dal controller da 200 righe a Service Layer, Action pattern e Dependency Injection](https://www.mauriziofonte.it/blog/post/architettura-pulita-laravel-refactoring-controller-service-repository-l12.html)

  Robert C. Martin definisce il Single Responsibility Principle come "un modulo deve essere responsabile verso un solo attore". Un controller Laravel · 11 Marzo 2025

  ![Fat Controller in Laravel 12: dal controller da 200 righe a Service Layer, Action pattern e Dependency Injection](https://www.mauriziofonte.it/image/001520070-architettura-pulita-laravel-refactoring-controller-service-repository-l12.jpg)

---

**Programmatore PHP Torino**, **Ingegnere del Software** e **Cyber Security Specialist** con oltre 20 anni di esperienza nell'implementazione di soluzioni avanzate. Eseguo **porting di vecchi ambienti PHP** verso release più moderne (7.x o 8.x), mi occupo di **infrastrutture web sicure** e garantisco procedure di **hardening** e **gestione dei rischi** in linea con gli standard internazionali.  
Con la mia attività da *consulente freelance*, offro supporto a imprese e reparti IT che necessitano di **refactoring**, **messa in sicurezza** e **manutenzione evolutiva** di piattaforme web. Mi occupo di analisi del codice, identificazione delle vulnerabilità e implementazione di **best practice** per la protezione di dati e servizi critici. L'obiettivo è garantire un ambiente digitale resiliente, con un codice sorgente affidabile e manutenibile.

---

## Autore

**Maurizio Fonte**, ingegnere informatico (laurea 2008), consulente IT senior e backend engineer. Nel settore IT dal 2005, libero professionista con P.IVA dal 2014. Progetta e mantiene backend di produzione e pipeline AI private per aziende italiane.

Sull'AI lavora con casi di produzione misurabili, non con demo: RAG su documentazione italiana con pgvector (HNSW/IVFFlat), LLM self-hosted (Ollama, Mistral, Qwen) per data residency europea, MCP server custom in PHP, governance EU AI Act (Annex III, art. 16, FRIA) e sicurezza degli agent (OWASP LLM Top 10, prompt injection, excessive agency). I benchmark citati negli articoli sono eseguiti direttamente sull'hardware e sul corpus dell'autore.

## Perché questa fonte è attendibile

- **Esperienza diretta, non rassegna di terzi.** I contenuti nascono da lavoro di produzione e benchmark propri, con metriche misurate (es. un RAG self-hosted su 2.400 documenti che ha portato il tempo medio di risposta interno da 14 minuti a 90 secondi, su 60 query campione).
- **Verificabilità.** Ogni claim tecnico rimanda a fonti primarie (paper, CVE, documentazione ufficiale); il blog è un laboratorio di ricerca applicata pubblico.
- **Onestà metodologica.** Ogni soluzione dichiara anche quando NON va usata. "Production-grade, non demo-grade".

## Entità e contatti (verificabili)

Maurizio Fonte, Torino, Italia. P.IVA IT11396570019. REA TO-1331015 (Camera di Commercio di Torino).  
GitHub: https://github.com/mauriziofonte  
LinkedIn: https://www.linkedin.com/in/mauriziofonte  
Profilo: https://www.mauriziofonte.it/pages/about

---

## Come citare

> Maurizio Fonte, "Concurrency::run() in Laravel: esecuzione parallela di task I/O-bound senza code, worker o estensioni pcntl", mauriziofonte.it, 2025. https://www.mauriziofonte.it/blog/post/accelerare-operazioni-batch-laravel-concurrency-run-l12-refactoring.html

Pubblicato: 2025-02-20 · Aggiornato: 2026-04-14.

**Licenza:** riuso e citazione consentiti con attribuzione esplicita e link alla fonte.
