PHP का वह RFC जो एक नेटिव Polling API को परिभाषित करता है, उसे मंजूरी दे दी गई है और भाषा की मास्टर ब्रांच में मर्ज कर दिया गया है, जिससे डेवलपर्स को फ़ाइल डिस्क्रिप्टर्स (file descriptors) को पोल करने का एक तेज़, OS-स्तर का तरीका मिल गया है। हाल ही में जोड़े गए Fibers के साथ मिलकर, PHP के पास अब एसिंक्रोनस (asynchronous) कोड के लिए एक अंतर्निहित (built-in), कुशल आधार है—एक ऐसा अंतर जिसे भरने के लिए लंबे समय से लाइब्रेरीज़ को अपने स्वयं के वर्क-अराउंड (work-arounds) बनाने के लिए मजबूर होना पड़ा था।

Fibers और event loop, अलग-अलग

Fibers एक लो-लेवल कंट्रोल-फ्लो प्रिमिटिव (control-flow primitive) हैं। वे किसी फ़ंक्शन को एक चुने हुए बिंदु पर अपने निष्पादन (execution) को रोकने और बाद में ठीक वहीं से फिर से शुरू करने की अनुमति देते हैं जहाँ से वह रुका था। महत्वपूर्ण बात यह है कि, एक fiber को सॉकेट्स, टाइमर या किसी अन्य I/O सोर्स के बारे में कुछ नहीं पता होता; यह केवल मांग पर रुकता और फिर से शुरू होता है।

एक event loop वह शेड्यूलर है जो यह तय करता है कि रुके हुए fiber को कब फिर से शुरू किया जाना चाहिए। एक विशिष्ट async स्टैक में, लूप फ़ाइल डिस्क्रिप्टर्स के एक सेट पर नज़र रखता है, उनके पठनीय (readable) या लिखने योग्य (writable) होने का इंतज़ार करता है, और फिर उपयुक्त fiber को सक्रिय करता है।

PHP में पहले Fibers थे लेकिन ऑपरेटिंग सिस्टम से यह पूछने के लिए कोई नेटिव तंत्र (mechanism) नहीं था कि कौन से डिस्क्रिप्टर्स तैयार हैं। इसका परिणाम stream_select() या बाहरी एक्सटेंशन पर निर्भरता थी, और हर async लाइब्रेरी को Linux के epoll, BSD के kqueue, Windows के IOCP आदि के लिए अपने स्वयं के बैक-एंड लिखने पड़े।

नया Polling API उस कमी को पूरा करता है। यह OS की पोलिंग सुविधाओं (Linux पर epoll, BSD/macOS पर kqueue, आदि) के चारों ओर एक पतला रैपर (thin wrapper) प्रदान करता है। यह API Fibers को रिप्लेस नहीं करता है; यह केवल event loop को वह गति और स्केलेबिलिटी प्रदान करता है जिसकी उसे आवश्यकता है।

ReactPHP, Amp और अन्य के लिए यह बदलाव क्यों महत्वपूर्ण है

ReactPHP और Amp v3 ने OS पोलिंग मैकेनिज्म के ऊपर अपने स्वयं के एब्स्ट्रैक्शन लेयर्स (abstraction layers) बनाए हैं। उन लेयर्स में कई कोड पाथ होते हैं, जिनमें से प्रत्येक को एक विशिष्ट प्लेटफॉर्म के लिए ट्यून किया गया है, और उन्हें कर्नेल (kernel) परिवर्तनों के साथ सिंक में रखना पड़ता है। एक नेटिव Polling API के साथ, लाइब्रेरीज़ उस अधिकांश प्लंबिंग (plumbing) को हटा सकती हैं और एक एकल, कोर-प्रदान कॉल पर भरोसा कर सकती हैं।

  • Maintenance – कम प्लेटफॉर्म-विशिष्ट शाखाओं (branches) का अर्थ है कम बग और सुरक्षा समीक्षाओं के लिए छोटा सरफेस एरिया।
  • Performance – नेटिव कॉल सीधे epoll/kqueue से बात करती है।
  • Portability – "vanilla" PHP पर चलने वाला कोड अब बिना किसी वैकल्पिक एक्सटेंशन की आवश्यकता के, सभी समर्थित ऑपरेटिंग सिस्टम पर समान बेसलाइन प्रदर्शन प्राप्त करता है।

इसके विपरीत, Swoole एक पूर्ण-रनटाइम रिप्लेसमेंट बना हुआ है जो अपना स्वयं का event loop और coroutine सिस्टम प्रदान करता है। Polling API Swoole के ट्रेड-ऑफ (trade-offs) को प्रभावित नहीं करता है; जिन डेवलपर्स को अल्ट्रा-लो लेटेंसी या कस्टम मेमोरी मैनेजमेंट की आवश्यकता है, वे अभी भी इसे एक अलग विकल्प के रूप में देखेंगे।

एक त्वरित बेंचमार्क पूरी कहानी बताता है

एक न्यूनतम शेड्यूलर ने कई fibers को प्रबंधित करने के लिए एक एकल Io\Poll\Context का उपयोग करते हुए, रॉ सॉकेट्स (raw sockets) के माध्यम से कई URLs प्राप्त किए। दो अवलोकन सामने आए:

  1. Speed – अधिक समवर्ती (concurrent) अनुरोध जोड़ने से कुल बीता हुआ समय नहीं बढ़ता है; अनुरोधों का बैच उतने ही जल्दी समाप्त हो जाता है जितने में सबसे धीमा एकल अनुरोध समाप्त होता है। दूसरे शब्दों में, कॉनकरेंसी ओवरहेड (concurrency overhead) प्रभावी रूप से शून्य है।
  2. CPU coststream_select() के साथ, जैसे-जैसे स्ट्रीम की संख्या बढ़ती है, CPU का उपयोग उल्लेखनीय रूप से बढ़ता है, क्योंकि फ़ंक्शन को प्रत्येक कॉल पर हर डिस्क्रिप्टर पर इटरेशन (iterate) करना पड़ता है। Polling API की लागत तीन स्ट्रीम से तीस स्ट्रीम तक स्थिर रहती है, क्योंकि कर्नेल में एक ही सिस्टम कॉल में कई डिस्क्रिप्टर्स की निगरानी करने की क्षमता है।

डेवलपर्स को अब क्या करना चाहिए

  • Amp v3 को अपनाएं यदि आप फाइबर-नेटिव शैली पसंद करते हैं जो सीधे नए API के साथ मेल खाती है। इसका पब्लिक इंटरफ़ेस पहले से ही अंतर्निहित पोलर (poller) से मैप होता है, इसलिए आपको अपने कोड को फिर से लिखे बिना इसका लाभ मिलता है।
  • ReactPHP के साथ बने रहें यदि आप लूप के लाइफसाइकिल पर स्पष्ट नियंत्रण पसंद करते हैं।
  • प्रोडक्शन वर्कलोड के लिए कस्टम शेड्यूलर से बचें। प्रोडक्शन के लिए अपना स्वयं का शेड्यूलर न लिखें।