0Pricing
PHP Academy · Lezione

Il modello di concorrenza di PHP

Comprendete l'I/O bloccante e quando l'asincronia è utile.

Il modello di concorrenza di PHP è una lezione PHP Academy gratuita su CoddyKit. Questa è la lezione 1 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento PHP Academy, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso PHP Academy include 4 lezioni in totale.

PHP è sincrono per impostazione predefinita

Il PHP classico esegue una richiesta per processo, dall'inizio alla fine, con I/O bloccante. Una chiamata file_get_contents() a un'API lenta blocca l'intero script finché non arrivano i byte. Il modello shared-nothing (un processo nuovo per ogni richiesta, con lo stato eliminato al termine) è straordinariamente semplice, ma implica che un singolo worker possa fare esattamente una cosa alla volta. Questa lezione mostra dove ciò crea problemi e dove l'asincronia può essere d'aiuto.

I/O bloccante: misurazione

Osservate il tempo trascorso dominato dall'attesa, non dall'elaborazione. Tre richieste sequenziali da un secondo richiedono circa 3 secondi, anche se la CPU rimane inattiva per tutto il tempo.

<?php
$start = microtime(true);
foreach (['a', 'b', 'c'] as $job) {
    usleep(1_000_000); // simulate a 1s blocking network call
    echo "done $job\n";
}
printf("elapsed: %.2fs\n", microtime(true) - $start); // ~3.00s

CPU-bound e I/O-bound

La concorrenza aiuta solo il lavoro I/O-bound, cioè il tempo trascorso in attesa della rete, del disco o del database. Per il lavoro CPU-bound (calcolo di hash, ridimensionamento di immagini, parsing), un singolo thread è già saturo: l'asincronia aggiunge solo overhead di scheduling. Prima fate una diagnosi:

  • Molte chiamate HTTP o query al database lente → l'asincronia offre grandi vantaggi.
  • Cicli numerici stretti → usate il parallelismo (processi/thread), non un event loop.

Come PHP ha gestito la scalabilità finora

Storicamente, PHP ha gestito la scalabilità con la concorrenza a livello di processo: PHP-FPM mantiene un pool di processi worker, ognuno dei quali gestisce una richiesta alla volta, mentre il sistema operativo li multiplexa. Questa è vera concorrenza tra richieste, ma non offre nulla all'interno di una richiesta: con il normale codice bloccante non è comunque possibile eseguire in parallelo 50 chiamate API all'interno dello stesso handler.

L'idea dell'event loop

Async PHP introduce un event loop: un singolo thread che registra le operazioni I/O come non bloccanti, quindi rimane in attesa in stream_select()/epoll finché una di esse non è pronta, invocando i callback man mano che arrivano i dati. Un solo thread gestisce migliaia di socket perché non rimane mai inattivo in attesa di uno soltanto.

<?php
// Conceptual loop: poll many non-blocking streams at once
$streams = openManyNonBlockingSockets();
while ($streams) {
    $read = $streams; $write = $except = [];
    stream_select($read, $write, $except, null); // sleeps until ANY is ready
    foreach ($read as $s) {
        handleReadyStream($s); // runs only the sockets that have data now
    }
}

Cooperativo, non preemptive

Async PHP è cooperativo: le attività vengono eseguite finché non cedono volontariamente il controllo in corrispondenza di un punto di I/O. Non c'è prelazione, quindi una chiamata bloccante lunga o un ciclo stretto che usa la CPU blocca l'intero loop — tutte le altre attività restano senza tempo di esecuzione. Regola d'oro: non invochi mai funzioni bloccanti (sleep, PDO bloccante, file_get_contents) all'interno di un'attività dell'event loop. Utilizzi gli equivalenti asincroni del loop.

Tre approcci in PHP

PHP moderno offre un toolkit a strati:

  • Fibers (PHP 8.1, core) — una primitiva di basso livello per sospendere e riprendere lo stack delle chiamate. È l'elemento costitutivo, non un framework completo.
  • ReactPHP / Amp — event loop in userland costruiti sugli stream (e ora sulle Fibers) per l'I/O non bloccante senza estensioni.
  • Swoole / OpenSwoole — un'estensione C che fornisce coroutine, un server ad alte prestazioni e chiamate bloccanti intercettate.

Rilevi ciò che è disponibile a runtime prima di scegliere una strategia.

<?php
echo 'Fibers: ' . (class_exists('Fiber') ? 'yes' : 'no'), PHP_EOL;
echo 'Swoole ext: ' . (extension_loaded('swoole') ? 'yes' : 'no'), PHP_EOL;
echo 'parallel ext: ' . (extension_loaded('parallel') ? 'yes' : 'no'), PHP_EOL;
echo 'PHP ' . PHP_VERSION, PHP_EOL;

Le promise rappresentano valori futuri

Prima delle Fibers, PHP asincrono esponeva i risultati in sospeso come promise: un segnaposto per un valore che viene risolto in seguito. Si collegano callback tramite then(). Funziona, ma porta a catene annidate; le Fibers permettono alle librerie di nascondere questa complessità dietro un await dall'aspetto sincrono.

<?php
use React\Promise\Promise;

$promise = new Promise(function ($resolve) {
    // resolved later when I/O completes
    $resolve(42);
});
$promise->then(function ($value) {
    echo "got $value\n";
});

Concorrenza e parallelismo

Sia preciso:

  • Concorrenza — molte attività in corso, eseguite a turno su un singolo thread (event loop). Ideale per l'I/O.
  • Parallelismo — molte attività eseguite simultaneamente su più core (processi, l'estensione parallel, task worker di Swoole). Necessario per il lavoro CPU.

Un event loop offre concorrenza, non parallelismo. Il frammento seguente mostra il parallelismo a livello di processi con proc_open: tre worker vengono eseguiti contemporaneamente in processi separati del sistema operativo.

<?php
$procs = [];
foreach (range(1, 3) as $i) {
    // Each worker is a separate OS process -> real parallelism
    $procs[] = proc_open(
        "php -r 'usleep(500000); echo \"worker $i done\\n\";'",
        [1 => ['pipe', 'w']], $pipes
    );
}
foreach ($procs as $p) { proc_close($p); }
echo "all workers launched in parallel\n";

Quando NON ricorrere all'asincronia

L'asincronia ha dei costi: un worker di lunga durata significa che PHP non cancella più lo stato tra una richiesta e l'altra, quindi le perdite di memoria, le cache statiche e la staleness delle connessioni diventano una Sua responsabilità. Se un gestore di richieste esegue una query al DB e restituisce il risultato, PHP-FPM è più semplice e altrettanto veloce. Ricorra all'asincronia quando ha bisogno di fan-out di I/O, WebSockets/long polling, streaming o di un server persistente.

Parallelismo reale: ext-parallel e processi

Per il fan-out vincolato dalla CPU, PHP può eseguire un vero parallelismo a livello del sistema operativo. L'estensione parallel avvia thread di lavoro con memoria isolata; in alternativa proc_open/pcntl_fork generano processi. A differenza di un event loop, questi utilizzano più core simultaneamente: sono lo strumento giusto quando il collo di bottiglia è il calcolo, non l'attesa.

<?php
// Requires ext-parallel — runs tasks on separate threads/cores
use parallel\Runtime;

$runtime = new Runtime();
$future = $runtime->run(function (): int {
    $sum = 0;
    for ($i = 0; $i < 1_000_000; $i++) $sum += $i; // CPU work on another core
    return $sum;
});
echo $future->value(), PHP_EOL;

Verifica rapida

Che cosa accade se si chiama sleep(2) bloccante all'interno di un'attività dell'event loop?

Riepilogo

Ora dispone di un modello mentale della concorrenza in PHP:

  • PHP predefinito è sincrono, bloccante e shared-nothing; FPM scala tra le richieste, non all'interno di una singola richiesta.
  • L'asincronia aiuta il lavoro vincolato dall'I/O tramite un event loop a thread singolo che usa stream non bloccanti.
  • Il modello è cooperativo — non blocchi mai il loop; il lavoro CPU prolungato richiede parallelismo, non concorrenza.
  • Il toolkit PHP: Fibers (primitiva), ReactPHP/Amp (loop in userland + promise), Swoole (estensione per coroutine).

Domande Frequenti

La lezione «Il modello di concorrenza di PHP» è gratuita?

Sì — il testo completo di «Il modello di concorrenza di PHP» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso PHP Academy, passa a CoddyKit PRO. Il corso PHP Academy include 4 lezioni in totale.

Cosa imparerò in «Il modello di concorrenza di PHP»?

Comprendete l'I/O bloccante e quando l'asincronia è utile. Eserciti PHP Academy con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.

Ho bisogno di esperienza per iniziare PHP Academy?

Non è richiesta alcuna esperienza precedente. PHP Academy su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 1 di 4.

Quanto tempo richiede la lezione «Il modello di concorrenza di PHP»?

La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.

Posso scrivere ed eseguire codice in questa lezione PHP Academy?

Sì. Ogni lezione PHP Academy include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.

Tutte le lezioni di questo corso

  1. Il modello di concorrenza di PHP
  2. Fibers di PHP 8.1
  3. Event loop con ReactPHP
  4. Server ad alte prestazioni con Swoole
← Torna a PHP Academy