Kebenaran Tentang Async PHP: Fibers, epoll, dan PHP 8.6
Saya telah bekerja dengan Laravel selama bertahun-tahun. Saya menggunakan PHP sinkron (sync). Sebuah permintaan datang, proses berjalan, dan respons dikirim. Saya tidak pernah membutuhkan kode async.
Kemudian saya membaca tentang Polling API PHP 8.6 yang baru. Hal itu mengubah cara pandang saya terhadap segalanya.
Inilah yang saya pelajari tentang cara kerja async di balik layar.
Masalah I/O
Saat Anda memanggil sebuah API, proses PHP Anda menunggu.
Contoh:
$response = Http::get('https://api.example.com');
Jika panggilan tersebut memakan waktu 300ms, CPU Anda tidak melakukan apa-apa selama 300ms. Ia tetap dalam keadaan tidur (sleep state). Ini adalah blocking I/O.
Jika Anda memiliki tiga panggilan API:
- API A: 300ms
- API B: 400ms
- API C: 200ms
Total sekuensial: 900ms. Total async: 400ms (waktu dari panggilan yang paling lambat).
Async memungkinkan proses Anda melakukan pekerjaan lain sambil menunggu data.
Select vs. epoll
Untuk melakukan async, Anda perlu mengetahui socket mana yang datanya sudah siap.
select() PHP telah menggunakan
stream_select()sejak versi 4. Cara kerjanya adalah dengan meminta kernel untuk mengawasi daftar socket. Masalahnya: Setiap kali data tiba, Anda harus memindai seluruh daftar lagi. Ini adalah beban pemindaian ulang (rescan tax). Ia juga memiliki batas sekitar 1024 koneksi.epoll (Linux) / kqueue (macOS) Ini adalah fitur kernel. Alih-alih memindai daftar, kernel menyimpan daftar yang sudah siap (ready-list). Ia hanya memberi tahu Anda socket spesifik mana yang sudah siap. Ini dapat diskalakan hingga ribuan koneksi tanpa pekerjaan tambahan.
epoll bukanlah fitur PHP. Ini adalah fitur Linux. Go, Rust, dan Node.js semuanya menggunakannya.
Fibers: Tombol Jeda
PHP 8.1 memperkenalkan Fibers. Saya pikir Fibers akan bangun dengan sendirinya. Ternyata tidak.
Sebuah Fiber itu seperti video yang dijeda. Ia tetap dijeda sampai seseorang memanggil $fiber->resume().
Event Loop hanyalah sebuah potongan kode PHP yang memutuskan kapan harus memanggil resume().
Async I/O membutuhkan tiga bagian:
- Pause: Fibers (inti PHP 8.1)
- Decide: Event Loop (kode PHP biasa)
- Know: Kernel Polling (epoll/kqueue)
Sebelum PHP 8.6, PHP memiliki bagian "Pause" dan "Decide", tetapi bagian "Know" bergantung pada select() lama atau ekstensi C yang lambat.
PHP 8.6 menutup celah ini. Ia menghadirkan Polling API asli ke dalam inti (core). Sekarang, PHP dapat menggunakan epoll atau kqueue secara langsung tanpa ekstensi tambahan.
Kesimpulan
Jika Anda menggunakan Laravel dengan PHP-FPM, Anda tidak perlu mengubah apa pun saat ini.
Namun pahamilah ini: Async bukanlah sihir. Ia hanyalah cara cerdas untuk mengelola waktu tunggu.
Berhentilah hanya sekadar mengonsumsi kode. Jalankan skrip sederhana. Rusaklah. Begitulah cara Anda benar-benar belajar.
