একটি নেটিভ Polling API সংজ্ঞায়িত করার PHP RFC অনুমোদিত হয়েছে এবং ল্যাঙ্গুয়েজের মাস্টার ব্রাঞ্চে মার্জ করা হয়েছে, যা ডেভেলপারদের ফাইল ডেসক্রিপ্টর পোল করার জন্য একটি দ্রুত, OS-লেভেল পদ্ধতি প্রদান করছে। সম্প্রতি যুক্ত হওয়া Fibers-এর সাথে যুক্ত হয়ে, PHP এখন অ্যাসিনক্রোনাস কোডের জন্য একটি বিল্ট-ইন, দক্ষ ভিত্তি পেয়েছে—একটি ঘাটতি যা দীর্ঘকাল ধরে লাইব্রেরিগুলোকে তাদের নিজস্ব বিকল্প বা workaround তৈরি করতে বাধ্য করেছিল।
Fibers এবং event loop, আলাদাভাবে
Fibers হলো একটি লো-লেভেল কন্ট্রোল-ফ্লো প্রিমিটিভ। এগুলো একটি ফাংশনকে তার পছন্দমতো একটি বিন্দুতে নির্বাহ স্থগিত (suspend) করতে এবং পরে ঠিক যেখান থেকে থেমেছিল সেখান থেকেই পুনরায় শুরু (resume) করতে দেয়। গুরুত্বপূর্ণ বিষয় হলো, একটি fiber সকেট, টাইমার বা অন্য কোনো I/O সোর্স সম্পর্কে কিছুই জানে না; এটি কেবল প্রয়োজন অনুযায়ী থেমে যায় এবং পুনরায় শুরু হয়।
একটি event loop হলো সেই শিডিউলার যা সিদ্ধান্ত নেয় কখন একটি স্থগিত fiber-কে পুনরায় শুরু করতে হবে। একটি সাধারণ async স্ট্যাকে, লুপটি এক সেট ফাইল ডেসক্রিপ্টর পর্যবেক্ষণ করে, সেগুলো রিডেবল (readable) বা রাইটেবল (writable) হওয়ার জন্য অপেক্ষা করে এবং তারপর উপযুক্ত fiber-কে জাগিয়ে তোলে।
PHP-তে আগে Fibers ছিল কিন্তু অপারেটিং সিস্টেমকে কোন ডেসক্রিপ্টরগুলো প্রস্তুত তা জিজ্ঞাসা করার জন্য কোনো নেটিভ মেকানিজম ছিল না। এর ফলে stream_select() বা এক্সটার্নাল এক্সটেনশনের ওপর নির্ভর করতে হতো, এবং প্রতিটি async লাইব্রেরি শেষ পর্যন্ত Linux-এর epoll, BSD-এর kqueue, Windows-এর IOCP ইত্যাদির জন্য নিজস্ব ব্যাক-এন্ড লিখতে বাধ্য হতো।
নতুন Polling API সেই অভাব পূরণ করে। এটি অপারেটিং সিস্টেমের পোলিং সুবিধার (Linux-এ epoll, BSD/macOS-এ kqueue ইত্যাদি) চারপাশে একটি পাতলা র্যাপার (thin wrapper) হিসেবে কাজ করে। এই API Fibers-এর বিকল্প নয়; এটি কেবল event loop-কে প্রয়োজনীয় গতি এবং স্কেলেবিলিটি প্রদান করে।
কেন এই পরিবর্তন ReactPHP, Amp এবং অন্যান্যদের জন্য গুরুত্বপূর্ণ
ReactPHP এবং Amp v3 অপারেটিং সিস্টেমের পোলিং মেকানিজমের ওপর নিজস্ব অ্যাবস্ট্রাকশন লেয়ার তৈরি করেছে। সেই লেয়ারগুলোতে একাধিক কোড পাথ থাকে, যার প্রতিটি একটি নির্দিষ্ট প্ল্যাটফর্মের জন্য টিউন করা এবং সেগুলোকে কার্নেল পরিবর্তনের সাথে সামঞ্জস্যপূর্ণ রাখতে হয়। একটি নেটিভ Polling API থাকলে, লাইব্রেরিগুলো সেই সমস্ত জটিলতা (plumbing) বাদ দিতে পারবে এবং একটি মাত্র কোর-প্রদত্ত কলের ওপর নির্ভর করতে পারবে।
- Maintenance – প্ল্যাটফর্ম-নির্দিষ্ট ব্রাঞ্চ কম হওয়ার অর্থ হলো কম বাগ এবং সিকিউরিটি রিভিউয়ের জন্য ছোট পরিসর।
- Performance – নেটিভ কল সরাসরি epoll/kqueue-এর সাথে যোগাযোগ করে।
- Portability – "vanilla" PHP-তে চলা কোড এখন কোনো অতিরিক্ত এক্সটেনশনের প্রয়োজন ছাড়াই সমস্ত সমর্থিত অপারেটিং সিস্টেমে একই বেসলাইন পারফরম্যান্স পাবে।
বিপরীতে, Swoole একটি পূর্ণাঙ্গ রানটাইম রিপ্লেসমেন্ট হিসেবে থাকে যা নিজস্ব event loop এবং কোরুটিন সিস্টেম নিয়ে আসে। Polling API Swoole-এর কার্যপদ্ধতির ওপর কোনো প্রভাব ফেলে না; যেসব ডেভেলপার আল্ট্রা-লো ল্যাটেন্সি বা কাস্টম মেমরি ম্যানেজমেন্ট চান, তারা এটিকে এখনও একটি আলাদা বিকল্প হিসেবে বিবেচনা করবেন।
একটি দ্রুত বেঞ্চমার্ক যা চিত্রটি তুলে ধরে
একটি মিনিমাল শিডিউলার একাধিক fiber পরিচালনা করার জন্য একটি মাত্র Io\Poll\Context ব্যবহার করে র-সকেট (raw sockets) এর মাধ্যমে বেশ কিছু URL ফেচ করেছে। দুটি পর্যবেক্ষণ পাওয়া গেছে:
- Speed – আরও বেশি কনকারেন্ট রিকোয়েস্ট যোগ করলে মোট অতিবাহিত সময় বাড়ে না; রিকোয়েস্ট ব্যাচটি সবচেয়ে ধীরগতির একক রিকোয়েস্টের মতোই দ্রুত শেষ হয়। অন্য কথায়, কনকারেন্সি ওভারহেড কার্যত শূন্য।
- CPU cost –
stream_select()ব্যবহার করলে স্ট্রিমের সংখ্যা বাড়ার সাথে সাথে CPU ব্যবহার উল্লেখযোগ্যভাবে বৃদ্ধি পায়, কারণ প্রতিটি কলের সময় ফাংশনটিকে প্রতিটি ডেসক্রিপ্টরের ওপর দিয়ে ইটারেট করতে হয়। অন্যদিকে, কার্নেলের একটি মাত্র সিস্টেম কলের মাধ্যমে অনেক ডেসক্রিপ্টর মনিটর করার ক্ষমতার কারণে তিনটি থেকে ত্রিশটি স্ট্রিম থাকলেও Polling API-এর খরচ স্থির থাকে।
ডেভেলপারদের এখন কী করা উচিত
- Amp v3 গ্রহণ করুন যদি আপনি fiber-native স্টাইল পছন্দ করেন যা সরাসরি নতুন API-এর সাথে সামঞ্জস্যপূর্ণ। এর পাবলিক ইন্টারফেস ইতিমধ্যেই অন্তর্নিহিত পলারের (poller) সাথে ম্যাপ করা আছে, তাই কোড পুনরায় না লিখেই আপনি এর সুবিধা পাবেন।
- ReactPHP-তে থাকুন যদি আপনি লুপের লাইফসাইকেলের ওপর স্পষ্ট নিয়ন্ত্রণ পছন্দ করেন।
- প্রোডাকশন ওয়ার্কলোডের জন্য কাস্টম শিডিউলার এড়িয়ে চলুন। প্রোডাকশনের জন্য নিজের শিডিউলার লিখবেন না।
