Вся правда об асинхронном PHP: Fibers, epoll и PHP 8.6

Я годами работал с Laravel. Я использовал синхронный PHP. Приходит запрос, процесс выполняется, и отправляется ответ. Мне никогда не требовался асинхронный код.

Затем я прочитал о новом PHP 8.6 Polling API. Это изменило мой взгляд на вещи.

Вот что я узнал о том, как асинхронность работает «под капотом».

Проблема ввода-вывода (I/O)

Когда вы вызываете API, ваш PHP-процесс ждет. Пример: $response = Http::get('https://api.example.com');

Если этот вызов занимает 300 мс, ваш процессор ничего не делает в течение 300 мс. Он находится в состоянии ожидания. Это блокирующий ввод-вывод (blocking I/O).

Если у вас есть три вызова API:

  • API A: 300 мс
  • API B: 400 мс
  • API C: 200 мс

Общее время последовательно: 900 мс. Общее время асинхронно: 400 мс (время самого медленного вызова).

Асинхронность позволяет вашему процессу выполнять другую работу, пока ожидаются данные.

Select против epoll

Чтобы реализовать асинхронность, нужно знать, в каком сокете готовы данные.

1. select()

PHP использует stream_select() начиная с 4-й версии. Он работает, запрашивая ядро следить за списком сокетов. Проблема: каждый раз, когда приходят данные, вам приходится сканировать весь список заново. Это «налог на повторное сканирование» (rescan tax). Также существует ограничение — около 1024 соединений.

2. epoll (Linux) / kqueue (macOS)

Это функции ядра. Вместо сканирования списка ядро поддерживает список готовых сокетов (ready-list). Оно сообщает вам только о тех конкретных сокетах, которые готовы к работе. Это масштабируется до тысяч соединений без дополнительных затрат.

epoll — это не функция PHP. Это функция Linux. Go, Rust и Node.js — все они используют её.

Fibers: кнопка паузы

PHP 8.1 представил Fibers. Я думал, что Fibers будут «просыпаться» сами по себе. Но это не так.

Fiber — это как поставленное на паузу видео. Оно остается на паузе, пока кто-нибудь не вызовет $fiber->resume().

Event Loop — это просто фрагмент PHP-кода, который решает, когда вызвать resume().

Для асинхронного ввода-вывода (Async I/O) требуются три составляющие:

  • Пауза: Fibers (ядро PHP 8.1)
  • Решение: Event Loop (обычный PHP-код)
  • Знание: Kernel Polling (epoll/kqueue)

До PHP 8.6 у PHP были части «Пауза» и «Решение», но часть «Знание» полагалась на старый select() или медленные расширения на C.

PHP 8.6 устраняет этот пробел. Он внедряет нативный Polling API непосредственно в ядро. Теперь PHP может использовать epoll или kqueue напрямую без дополнительных расширений.

Итог

Если вы используете Laravel с PHP-FPM, вам сегодня не нужно ничего менять.

Но поймите одно: асинхронность — это не магия. Это просто умный способ управления временем ожидания.

Перестаньте просто потреблять код. Запустите простой скрипт. Сломайте его. Только так можно по-настоящему научиться.

Source: https://dev.to/alamriku/sync-php-developer-hisebe-async-php-bujhte-giye-yaa-shikhlaam-fibers-epoll-aar-php-86-462j