Async PHP-യെ കുറിച്ചുള്ള സത്യങ്ങൾ: Fibers, epoll, പിന്നെ PHP 8.6

വർഷങ്ങളായി ഞാൻ Laravel ഉപയോഗിക്കുന്നു. ഞാൻ ഉപയോഗിച്ചിരുന്നത് sync PHP ആയിരുന്നു. ഒരു request വരുന്നു, process പ്രവർത്തിക്കുന്നു, response തിരികെ നൽകുന്നു. എനിക്ക് ഒരിക്കലും async code ആവശ്യമായി വന്നില്ല.

പിന്നീട് ഞാൻ പുതിയ PHP 8.6 Polling API-യെ കുറിച്ച് വായിച്ചു. അത് കാര്യങ്ങളെ നോക്കിക്കാണുന്ന രീതി തന്നെ മാറ്റിമറിച്ചു.

async എങ്ങനെയാണ് ഉള്ളിൽ പ്രവർത്തിക്കുന്നത് എന്നതിനെക്കുറിച്ച് ഞാൻ പഠിച്ച കാര്യങ്ങൾ താഴെ നൽകുന്നു.

The IO Problem

നിങ്ങൾ ഒരു API call ചെയ്യുമ്പോൾ, നിങ്ങളുടെ PHP process കാത്തുനിൽക്കുന്നു. Example: $response = Http::get('https://api.example.com');

ആ call നടക്കാൻ 300ms എടുക്കുകയാണെങ്കിൽ, ആ 300ms നേരം നിങ്ങളുടെ CPU ഒന്നും ചെയ്യുന്നില്ല. അത് ഒരു sleep state-ൽ തുടരുന്നു. ഇതാണ് blocking I/O.

നിങ്ങൾക്ക് മൂന്ന് API calls ഉണ്ടെങ്കിൽ:

  • API A: 300ms
  • API B: 400ms
  • API C: 200ms

Sequential total: 900ms. Async total: 400ms (ഏറ്റവും കൂടുതൽ സമയം എടുക്കുന്ന call-ന്റെ സമയം).

ഡാറ്റയ്ക്കായി കാത്തുനിൽക്കുമ്പോൾ തന്നെ മറ്റ് ജോലികൾ ചെയ്യാൻ async നിങ്ങളുടെ process-നെ അനുവദിക്കുന്നു.

Select vs. epoll

Async ചെയ്യാൻ, ഏത് socket-ലാണ് ഡാറ്റ തയ്യാറായിട്ടുള്ളതെന്ന് അറിയേണ്ടതുണ്ട്.

  1. select() PHP version 4 മുതൽ stream_select() ഉപയോഗിക്കുന്നുണ്ട്. sockets-ന്റെ ഒരു ലിസ്റ്റ് നിരീക്ഷിക്കാൻ kernel-നോട് ആവശ്യപ്പെടുന്ന രീതിയിലാണ് ഇത് പ്രവർത്തിക്കുന്നത്. പ്രശ്നം: ഓരോ തവണ ഡാറ്റ വരുമ്പോഴും, നിങ്ങൾ ആ ലിസ്റ്റ് മുഴുവനായി വീണ്ടും scan ചെയ്യേണ്ടി വരുന്നു. ഇതിനെ ഒരു rescan tax എന്ന് വിളിക്കാം. കൂടാതെ ഇതിന് ഏകദേശം 1024 connections എന്ന പരിധിയുമുണ്ട്.

  2. epoll (Linux) / kqueue (macOS) ഇവ kernel ഫീച്ചറുകളാണ്. ഒരു ലിസ്റ്റ് മുഴുവനായി scan ചെയ്യുന്നതിന് പകരം, kernel ഒരു ready-list സൂക്ഷിക്കുന്നു. ഏത് പ്രത്യേക sockets ആണ് തയ്യാറുള്ളതെന്ന് ഇത് മാത്രം നിങ്ങളോട് പറയുന്നു. അധികം അധ്വാനമില്ലാതെ തന്നെ ആയിരക്കണക്കിന് connections കൈകാര്യം ചെയ്യാൻ ഇതിന് സാധിക്കും.

epoll എന്നത് ഒരു PHP ഫീച്ചറല്ല. അതൊരു Linux ഫീച്ചറാണ്. Go, Rust, Node.js എന്നിവയെല്ലാം ഇത് ഉപയോഗിക്കുന്നു.

Fibers: The Pause Button

PHP 8.1 ആണ് Fibers അവതരിപ്പിച്ചത്. Fibers തനിയെ ഉണരുമെന്നാണ് ഞാൻ കരുതിയത്. എന്നാൽ അവ അങ്ങനെയല്ല ചെയ്യുന്നത്.

ഒരു Fiber എന്നത് paused ആയ ഒരു വീഡിയോ പോലെയാണ്. ആരെങ്കിലും $fiber->resume() എന്ന് വിളിക്കുന്നത് വരെ അത് paused അവസ്ഥയിൽ തന്നെ തുടരും.

ഒരു Event Loop എന്നത് എപ്പോഴാണ് resume() വിളിക്കേണ്ടതെന്ന് തീരുമാനിക്കുന്ന ഒരു PHP code മാത്രമാണ്.

Async I/O-യ്ക്ക് മൂന്ന് ഭാഗങ്ങൾ ആവശ്യമാണ്:

  • Pause: Fibers (PHP 8.1 core)
  • Decide: The Event Loop (Plain PHP code)
  • Know: Kernel Polling (epoll/kqueue)

PHP 8.6-ന് മുമ്പ്, PHP-യിൽ "Pause", "Decide" എന്നീ ഭാഗങ്ങൾ ഉണ്ടായിരുന്നു, എന്നാൽ "Know" എന്ന ഭാഗം പഴയ select() അല്ലെങ്കിൽ സാവധാനത്തിലുള്ള C extensions എന്നിവയെയാണ് ആശ്രയിച്ചിരുന്നത്.

PHP 8.6 ഈ വിടവ് നികത്തുന്നു. ഇത് ഒരു native Polling API കോറിലേക്ക് കൊണ്ടുവരുന്നു. ഇപ്പോൾ, അധികമായ extensions ഇല്ലാതെ തന്നെ PHP-ക്ക് നേരിട്ട് epoll അല്ലെങ്കിൽ kqueue ഉപയോഗിക്കാൻ കഴിയും.

The Takeaway

നിങ്ങൾ Laravel PHP-FPM ഉപയോഗിക്കുന്നുണ്ടെങ്കിൽ, ഇന്ന് തന്നെ ഒന്നും മാറ്റേണ്ടതില്ല.

പക്ഷേ ഇത് മനസ്സിലാക്കുക: Async എന്നത് ഒരു മാന്ത്രികവിദ്യയല്ല. കാത്തുനിൽക്കുന്ന സമയം (waiting time) കൈകാര്യം ചെയ്യാനുള്ള ഒരു ബുദ്ധിപരമായ മാർഗ്ഗം മാത്രമാണത്.

വെറുതെ കോഡ് വായിച്ചു പോകാതെ, ഒരു സിമ്പിൾ സ്ക്രിപ്റ്റ് റൺ ചെയ്യുക. അത് തെറ്റിച്ചു നോക്കുക (Break it). അങ്ങനെയാണ് നിങ്ങൾ യഥാർത്ഥത്തിൽ പഠിക്കുന്നത്.

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