W3docs

Функция PHP mysqli_poll()

Функция PHP mysqli_poll(): синтаксис, параметры, возвращаемые значения и пример опроса асинхронных соединений MySQL.

Функция mysqli_poll() позволяет ожидать результатов сразу нескольких соединений MySQL и определять, какие из них завершили выполнение асинхронного запроса. Это связующее звено между запуском неблокирующих запросов и получением их результатов без блокировки всего скрипта на самом медленном из них.

Что делает mysqli_poll()

При обычном выполнении запроса PHP останавливается и ждёт ответа от MySQL. При использовании асинхронных запросов (запущенных с флагом MYSQLI_ASYNC) запрос отправляется, но скрипт продолжает работу. Возникает вопрос: как узнать, когда результат готов к чтению? На него отвечает mysqli_poll().

Вы передаёте ей список соединений, и она блокируется до тех пор, пока хотя бы одно из них не будет готово вернуть результат (или пока не истечёт таймаут). Затем функция сообщает, какие соединения готовы, и вы получаете их результаты с помощью reap_async_query().

Это особенно важно, когда нужно выполнять несколько независимых запросов параллельно — например, запрашивать две разные базы данных или одновременно запускать несколько медленных отчётов. Вместо того чтобы выполнять каждый запрос последовательно, вы запускаете их все и позволяете им работать одновременно.

Важно: mysqli_poll() работает только с драйвером mysqlnd. С более старым драйвером libmysql она недоступна. Функция является только процедурной — объектно-ориентированного метода $mysqli->poll() не существует; всегда вызывайте её как mysqli_poll(...).

Синтаксис

mysqli_poll(
    array &$read,
    array &$error,
    array &$reject,
    int $seconds,
    int $microseconds = 0
): int|false

Параметры

ПараметрОписание
$readСписок соединений для проверки наличия результатов. Передаётся по ссылке — при возврате перезаписывается и содержит только соединения с готовыми результатами.
$errorПерезаписывается и содержит соединения, в которых произошла ошибка.
$rejectПерезаписывается и содержит отклонённые соединения (без ожидающего асинхронного запроса).
$secondsМаксимальное количество секунд ожидания.
$microsecondsДополнительные микросекунды ожидания (необязательно, по умолчанию 0).

Возвращаемое значение

Возвращает количество готовых соединений в случае успеха или false при ошибке. Возврат 0 означает, что таймаут истёк до того, как какое-либо соединение стало готовым — это не является ошибкой.

Как использовать функцию mysqli_poll()

Шаблон всегда состоит из трёх шагов:

  1. Открыть по одному соединению на каждый запрос, который нужно выполнить параллельно.
  2. Запустить каждый запрос с флагом MYSQLI_ASYNC, чтобы он не блокировал выполнение.
  3. В цикле вызывать mysqli_poll() для ожидания следующего завершившегося соединения и получения его результата.
<?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();
?>

Несмотря на то что первый запрос ждёт 1 секунду, а второй — 2 секунды, весь скрипт завершается примерно за 2 секунды, а не за 3 — оба запроса выполнялись одновременно. Поскольку запрос на 1 секунду завершается первым, вывод следующий:

orders done
reports done

Что делает код, шаг за шагом

  • Открываются два соединения, потому что каждое соединение может выполнять только один асинхронный запрос одновременно.
  • query(..., MYSQLI_ASYNC) отправляет каждый запрос и немедленно возвращает управление, не ожидая ответа.
  • Перед каждым вызовом mysqli_poll() мы копируем $pending в $read, $error и $reject, потому что функция перезаписывает эти массивы по ссылке. $read возвращается с готовыми соединениями, $error — с неудачными, $reject — с теми, у которых нет ожидающего запроса.
  • Для каждого готового соединения вызывается reap_async_query() для получения набора результатов, после чего соединение удаляется из $pending, чтобы не опрашивать его снова.
  • Цикл завершается, когда все запросы получены.

Примечание: Для сложных асинхронных нагрузок рассмотрите библиотеки цикла событий, такие как ReactPHP или Swoole, которые предоставляют более надёжную архитектуру, чем ручное написание цикла опроса.

Связанные функции

  • reap_async_query() — получить результат соединения, которое mysqli_poll() отметила как готовое.
  • query() — выполнить запрос (добавьте MYSQLI_ASYNC, чтобы сделать его неблокирующим).
  • multi_query() — выполнить несколько инструкций за один вызов для одного соединения.
  • connect_errno — проверить, завершилась ли попытка подключения ошибкой.

Заключение

mysqli_poll() — это элемент, который делает параллельные запросы MySQL практичными в PHP: она ожидает результатов от множества соединений одновременно и сообщает, какие из них готовы к чтению. Используйте её вместе с асинхронными запросами MYSQLI_ASYNC и reap_async_query(), помните, что требуется драйвер mysqlnd, и вы сможете сократить общее время выполнения нескольких независимых запросов примерно до времени самого медленного из них.

Практика

Практика
Какие утверждения о функции PHP mysqli_poll() верны?
Какие утверждения о функции PHP mysqli_poll() верны?
Was this page helpful?