Funzione PHP mysqli_poll()
Guida alla funzione PHP mysqli_poll(): sintassi, parametri, valori restituiti e come monitorare connessioni MySQL asincrone con un esempio completo.
La funzione mysqli_poll() consente di attendere su più connessioni MySQL contemporaneamente e di scoprire quali di esse hanno completato l'esecuzione di una query asincrona. È il ponte tra l'avvio di query non bloccanti e la raccolta dei loro risultati senza bloccare l'intero script sulla connessione più lenta.
Cosa fa mysqli_poll()
Quando si esegue una query nel modo normale, PHP si ferma e attende finché MySQL risponde. Con le query asincrone (avviate con il flag MYSQLI_ASYNC), la query viene inviata ma lo script continua l'esecuzione. Il problema diventa: come faccio a sapere quando un risultato è pronto per essere letto? È proprio a questo che risponde mysqli_poll().
Si passa un elenco di connessioni e la funzione blocca l'esecuzione fino a quando almeno una di esse ha un risultato in attesa (o fino allo scadere di un timeout). Poi indica quali connessioni sono pronte e si raccolgono i loro risultati con reap_async_query().
Questo è utile quando occorre eseguire più query indipendenti in parallelo — ad esempio, interrogare due database diversi o eseguire più report lenti contemporaneamente. Invece di pagare il costo di ogni query una dopo l'altra, si avviano tutte e le si lascia eseguire in modo concorrente.
Importante: mysqli_poll() funziona solo con il driver mysqlnd. Non è disponibile con il vecchio driver libmysql. È inoltre solo procedurale — non esiste un metodo orientato agli oggetti $mysqli->poll(); va sempre chiamata come mysqli_poll(...).
Sintassi
mysqli_poll(
array &$read,
array &$error,
array &$reject,
int $seconds,
int $microseconds = 0
): int|falseParametri
| Parametro | Descrizione |
|---|---|
$read | Elenco di connessioni da verificare per i risultati. Passato per riferimento — al ritorno viene riscritto per contenere solo le connessioni con un risultato pronto. |
$error | Riscritto per contenere le connessioni su cui si è verificato un errore. |
$reject | Riscritto per contenere le connessioni rifiutate (nessuna query asincrona in attesa su di esse). |
$seconds | Numero massimo di secondi da attendere. |
$microseconds | Microsecondi aggiuntivi da attendere (facoltativo, predefinito 0). |
Valore restituito
Restituisce il numero di connessioni pronte in caso di successo, oppure false in caso di errore. Un valore restituito di 0 significa che il timeout è scaduto prima che qualsiasi connessione diventasse pronta — non è un errore.
Come usare la funzione mysqli_poll()
Il pattern è sempre composto da tre passaggi:
- Aprire una connessione per ogni query che si vuole eseguire in parallelo.
- Avviare ogni query con il flag
MYSQLI_ASYNCin modo che non blocchi. - Eseguire un ciclo, chiamando
mysqli_poll()per attendere la connessione che termina per prima, e raccogliere il suo risultato.
<?php
// Open one connection per parallel query.
$conn1 = new mysqli("localhost", "user", "pass", "shop");
$conn2 = new mysqli("localhost", "user", "pass", "shop");
foreach ([$conn1, $conn2] as $c) {
if ($c->connect_errno) {
exit("Connect failed: " . $c->connect_error);
}
}
// Fire both queries asynchronously — neither call blocks.
$conn1->query("SELECT SLEEP(1), 'orders done' AS msg", MYSQLI_ASYNC);
$conn2->query("SELECT SLEEP(2), 'reports done' AS msg", MYSQLI_ASYNC);
$pending = [$conn1, $conn2];
while (!empty($pending)) {
// Copies that mysqli_poll() will rewrite by reference.
$read = $pending;
$error = $pending;
$reject = $pending;
// Block up to 5 seconds for at least one connection to become ready.
if (mysqli_poll($read, $error, $reject, 5) === false) {
echo "Poll failed.\n";
break;
}
// $read now holds only the connections with a result waiting.
foreach ($read as $conn) {
if ($result = $conn->reap_async_query()) {
$row = $result->fetch_assoc();
echo $row['msg'] . "\n";
$result->free();
} else {
echo "Query error: " . $conn->error . "\n";
}
// Remove this connection from the pending list.
$pending = array_filter($pending, fn($c) => $c !== $conn);
}
}
$conn1->close();
$conn2->close();
?>Anche se la prima query attende 1 secondo e la seconda 2 secondi, l'intero script termina in circa 2 secondi, non 3 — le due query sono state eseguite contemporaneamente. Poiché la query da 1 secondo termina per prima, l'output è:
orders done
reports doneCosa fa il codice, passo per passo
- Si aprono due connessioni perché ogni connessione può eseguire solo una query asincrona alla volta.
query(..., MYSQLI_ASYNC)invia ogni query e ritorna immediatamente invece di attendere.- Prima di ogni chiamata a
mysqli_poll()si copia$pendingin$read,$errore$reject, perché la funzione riscrive quegli array per riferimento.$readritorna contenendo solo le connessioni pronte,$errorquelle fallite e$rejectquelle senza query in attesa. - Per ogni connessione pronta si chiama
reap_async_query()per raccogliere il set di risultati, poi si rimuove quella connessione da$pendingper non interrogarla di nuovo. - Il ciclo termina una volta che ogni query è stata raccolta.
Nota: Per carichi di lavoro asincroni complessi, si consiglia di considerare librerie event-loop come ReactPHP o Swoole, che forniscono architetture più robuste rispetto alla creazione manuale di un ciclo di polling.
Funzioni correlate
reap_async_query()— raccoglie il risultato di una connessione chemysqli_poll()ha segnalato come pronta.query()— esegue una query (aggiungereMYSQLI_ASYNCper renderla non bloccante).multi_query()— esegue più istruzioni in una sola chiamata su una singola connessione.connect_errno— verifica se un tentativo di connessione è fallito.
Conclusione
mysqli_poll() è l'elemento che rende pratico l'uso di query MySQL parallele in PHP: attende su molte connessioni contemporaneamente e indica quali sono pronte per essere lette. Abbinata a query MYSQLI_ASYNC e reap_async_query(), ricordando che richiede il driver mysqlnd, permette di ridurre il tempo totale di più query indipendenti approssimativamente al tempo della più lenta.