PHP هي واحدة من لغات التطوير الرئيسية على Badoo. في مراكز البيانات الخاصة بنا ، تنشغل الآلاف من مراكز المعالج بتنفيذ ملايين أسطر شفرة PHP. نحن نتابع الأخبار عن كثب ونبحث بنشاط عن طرق لتحسين الإنتاجية ، حيث إن التحسين البسيط على أحجامنا يؤدي إلى توفير كبير في الموارد. أحد الأخبار الرئيسية عن أداء PHP هو ظهور JIT في الإصدار الثامن من اللغة. هذا ، بالطبع ، لا يمكن أن يبقى دون انتباهنا ، وقد ترجمنا مقالًا حول ما هو JIT ، وكيف سيتم تنفيذه في PHP ، ولماذا تقرر القيام بذلك وماذا نتوقع منه.إذا لم تكن قد تركت الكهف أو لم تأت من الماضي (في هذه الحالة ، مرحبًا بك) ، فأنت تعلم بالفعل أن PHP 8 ستحصل على JIT: في اليوم الآخر ، كان التصويت بهدوء وسلمي وأن الغالبية العظمى من المشاركين صوتوا مؤيدين للتنفيذ ، لذلك فقد تقرر .
في نوبة من الفرح ، يمكنك حتى تصور العديد من الحركات المجنونة كما في الصورة (وهذا ، بالمناسبة ، يسمى "ديترويت جيت":

الآن ، اجلس واقرأ هذه المقالة التي تكشف الأسطورة. أريد توضيح سوء الفهم المرتبط بماهية JIT وكيف يكون مفيدًا ، والتحدث عن كيفية عملها (ولكن ليس بتفصيل كبير بحيث لا تشعر بالملل).
بما أنني لا أعرف من سيقرأ المقال ، فسوف أتحول من أسئلة بسيطة إلى معقدة. إذا كنت تعرف بالفعل إجابة السؤال في العنوان ، فيمكنك تخطي الفصل المقابل بأمان.
ما هو جيت؟
يتم تطبيق PHP على أساس آلة افتراضية (نسميها Zend VM). تجمع اللغة شفرة مصدر PHP في تعليمات يفهمها الجهاز الظاهري (وتسمى هذه المرحلة مرحلة الترجمة). تسمى إرشادات الجهاز الظاهري التي تم الحصول عليها في مرحلة الترجمة الشفرة. في مرحلة التشغيل ، ينفذ Zend VM الشفرات ، مما يؤدي العمل المطلوب.
هذه الدائرة تعمل كبيرة. بالإضافة إلى ذلك ، تقوم أدوات مثل APC (قبل) و OpCache (اليوم) بتخزين نتائج مرحلة التجميع مؤقتًا ، لذلك لا يتم تنفيذ هذه المرحلة إلا إذا لزم الأمر.
باختصار ، JIT عبارة عن إستراتيجية تجميع في الوقت المناسب (في الوقت المناسب) ، يتم فيها ترجمة الشفرة لأول مرة إلى تمثيل وسيط ، والذي يتحول بعد ذلك إلى رمز آلة يعتمد على الهندسة المعمارية أثناء التنفيذ.
في PHP ، هذا يعني أن JIT ستنظر في إرشادات الجهاز الظاهري الذي تم استلامه في مرحلة التحويل البرمجي ككود تمثيل وسيط لإصدار الجهاز لن يتم تنفيذه بواسطة Zend VM ، لكن بواسطة المعالج مباشرة.
لماذا يحتاج PHP إلى JIT؟
قبل وقت قصير من ظهور PHP 7.0 ، كان التركيز الرئيسي لفريق PHP هو الأداء اللغوي. معظم التغييرات الرئيسية في PHP 7.0 كانت في PHPNG patch ، مما أدى إلى تحسن كبير في الطريقة التي يستخدم بها PHP الذاكرة والمعالج. منذ ذلك الحين ، يتعين على كل واحد منا إلقاء نظرة على أداء اللغة.
بعد إصدار الإصدار 7.0 من PHP ، استمرت تحسينات الأداء: تم تحسين جدول التجزئة (بنية البيانات الرئيسية في PHP) ، وتخصيص بعض أكواد شفرة التشغيل في Zend VM وتخصيص بعض التسلسلات في المترجم ، وتم تحسين Optimizer (مكون OpCache) باستمرار ، وتم تنفيذ العديد من التغييرات الأخرى.
الحقيقة القاسية هي أنه نتيجة لكل هذه التحسينات ، فإننا نقترب بسرعة من الحد الأقصى لفرص تحسين الإنتاجية.
يرجى ملاحظة: من خلال "الحد من فرص التحسين" أعني حقيقة أن المقايضات التي يجب إجراؤها لمزيد من التحسينات لم تعد جذابة. عندما يتعلق الأمر بتحسين الأداء ، نتحدث دائمًا عن المقايضات. في كثير من الأحيان ، من أجل الإنتاجية ، علينا أن نضحي بالبساطة. يود الجميع الاعتقاد بأن أبسط الكود هو الأسرع ، ولكن في العالم الحديث للبرمجة C هذا ليس كذلك. الأسرع في أغلب الأحيان هو الكود الذي تم إعداده للاستفادة من البنية الداخلية للهندسة المعمارية أو الهياكل المضمنة في النظام الأساسي / المترجم. البساطة وحدها لا تضمن أداء أفضل.
لذلك ، في هذه المرحلة ، فإن أفضل طريقة للضغط على أداء أكثر من PHP هي تنفيذ JIT.
هل تسرع JIT موقعي؟
على الأرجح ، بشكل ضئيل.
قد لا يكون هذا هو الجواب الذي كنت تتوقعه. والحقيقة هي أن تطبيقات PHP بشكل عام محدودة من خلال المدخلات / المخرجات (I / O bound) ، وأن JIT تعمل بشكل أفضل مع الكود الذي يقتصر على المعالج (CPU CPU).
ماذا تعني عبارة "محدود بواسطة I / O والمعالج"؟
لوصف خصائص الأداء الكلي لبعض الكود أو التطبيق ، نستخدم مصطلحي "محدود حسب المدخلات والمخرجات" و "مقيد بالمعالج".
أبسط تعريف:
- ستعمل التعليمات البرمجية المحددة بواسطة I / O بشكل أسرع بكثير إذا وجدنا طريقة لتحسين (تقليل ، تحسين) عمليات I / O التي تم إجراؤها ؛
- ستعمل التعليمات البرمجية الخاصة بالمعالج بشكل أسرع إذا وجدنا طريقة لتحسين (تقليل ، تحسين) الإرشادات التي ينفذها المعالج أو زيادة سرعة ساعة المعالج بطريقة سحرية.
يمكن أن يقتصر الرمز والتطبيق على I / O أو بواسطة المعالج أو كليهما.
بشكل عام ، تميل تطبيقات PHP إلى الحد من إدخال / إخراج: عنق الزجاجة الرئيسي هو عمليات الإدخال / الإخراج في كثير من الأحيان - الاتصال والقراءة والكتابة إلى قاعدة البيانات ، ذاكرات التخزين المؤقت ، الملفات ، المقابس ، إلخ.
كيف تبدو شفرة PHP الخاصة بالمعالج؟
ربما يكون بعض مبرمجي PHP جددًا في التعليمات البرمجية الخاصة بالمعالج نظرًا لطبيعة معظم تطبيقات PHP: عادةً ما يكونون بمثابة رابط لقاعدة البيانات أو ذاكرة التخزين المؤقت ، والتقاط وإنتاج كميات صغيرة من استجابات HTML / JSON / XML.
يمكنك إلقاء نظرة على قاعدة التعليمات البرمجية الخاصة بك والعثور على الكثير من التعليمات البرمجية التي لا علاقة لها بـ I / O ، وهو الكود الذي يستدعي الوظائف التي لا علاقة لها I / O. وقد تشعر بالارتباك لأن هذا لا يجعل تطبيقك مقيدًا بالمعالج ، على الرغم من أن الكود يحتوي على سطور لا تعمل مع I / O أكثر من العمل.
والحقيقة هي أن PHP هي واحدة من أسرع اللغات التي يتم تفسيرها. لا يوجد فرق ملحوظ بين استدعاء وظيفة لا تستخدم I / O في Zend VM وفي رمز الجهاز. بالطبع ، هناك بعض الاختلاف ، لكن كلاً من رمز الجهاز و Zend VM يستخدمان اتفاقية الاتصال ، لذلك لا يهم
-___()
قمت بالاتصال
-___()
في
-___()
أو في رمز الجهاز - لن يكون لهذا تأثير ملحوظ على أداء التطبيق بأكمله الذي يجعل المكالمة.
ملاحظة: بعبارات بسيطة ، اصطلاح استدعاء هو سلسلة من التعليمات المنفذة قبل إدخال وظيفة أخرى. في كلتا الحالتين ، تمرير اصطلاح استدعاء الوسائط إلى المكدس.أنت تسأل: "ماذا عن الحلقات ومكالمات الذيل والمزيد؟" PHP ذكي بما فيه الكفاية - وعند تشغيل Optimizer من OpCache ، سيتم تحويل الرمز بطريقة سحرية إلى إصدار أكثر كفاءة لما كتبته.
تجدر الإشارة هنا إلى أن JIT لن تغير اصطلاحات استدعاء Zend VM. يتم ذلك لأن PHP يجب أن يكون قادرًا على التبديل بين أوضاع JIT و VM في أي وقت (لذلك ، قرروا الاحتفاظ بالاتفاقيات الحالية). نتيجةً لذلك ، لن تعمل أي مكالمات تراها في كل مكان باستخدام JIT بشكل أسرع.
إذا كنت تريد معرفة شكل رمز PHP الخاص بالمعالج ، فقم هنا بالاطلاع على:
https://github.com/php/php-src/blob/master/Zend/bench.php . هذا مثال صارخ ، لكنه يظهر أن كل روعة JIT يتم كشفها في الرياضيات.
كان لجعل مثل هذا حل وسط المدقع لتسريع الحسابات الرياضية في PHP؟
لا. لقد فعلنا ذلك من أجل توسيع نطاق تطبيق اللغة (وتوسيع نطاقها).
لا نريد التباهي ، لكن PHP يسيطر على الويب. إذا كنت منخرطًا في تطوير الويب ولا تفكر في استخدام PHP في مشروعك التالي ، فأنت تفعل شيئًا خاطئًا (وفقًا لمطور PHP متحيز جدًا).
للوهلة الأولى ، قد يبدو أن تسريع الحسابات الرياضية في PHP له تطبيق ضيق للغاية. ومع ذلك ، يفتح هذا الطريق أمامنا ، على سبيل المثال ، للتعلم الآلي ، والعرض ثلاثي الأبعاد ، والعرض ثنائي الأبعاد (GUI) ، وتحليل البيانات.
لماذا لا يمكن تنفيذ ذلك في PHP 7.4؟
أعلاه ، وصفت JIT بأنها حل وسط شديد ، وأعتقد حقًا أن هذا: أحد أكثر استراتيجيات التصنيف صعوبةً بين كل ما هو موجود ، إن لم يكن الأكثر صعوبة. تنفيذ JIT هو زيادة كبيرة في التعقيد.
إذا سألت ديمتري ، مؤلف JIT ، عما إذا كان قد جعل PHP معقدًا ، فسوف يجيب: "لا ، أنا أكره التعقيد" (هذا اقتباس).
في الأساس ، "معقد" يعني "ما لا نفهمه". واليوم ، قليل من مطوري اللغات يفهمون حقًا التنفيذ الحالي لـ JIT.
يتقدم العمل على PHP 7.4 بسرعة ، وسيؤدي إدخال JIT في هذا الإصدار إلى حقيقة أن قلة قليلة فقط يمكنها تصحيح اللغة وإصلاحها وتحسينها. هذا غير مقبول بالنسبة لأولئك الذين صوتوا ضد JIT في PHP 7.4.
قبل إصدار PHP 8 ، سيتفهم الكثيرون منا تنفيذ JIT. هناك ميزات نرغب في تنفيذها ، وأدوات نود إعادة كتابتها للإصدار الثامن ، لذلك نحتاج أولاً إلى فهم JIT. نحن بحاجة إلى هذه المرة ، ونحن ممتنون للغاية لأن الأغلبية صوتت لصالحنا.
مجمع ليس مرادفا للفظيعة. يمكن أن يكون التعقيد جميلًا مثل سديم النجمة ، وهذا يتعلق فقط بـ JIT. بمعنى آخر ، حتى عندما يبدأ 20 شخصًا في فريقنا في فهم JIT ليس أسوأ من ديمتري ، فإن هذا لن يغير من تعقيد طبيعة JIT.
هل سيتباطأ تطوير PHP؟
لا يوجد سبب للاعتقاد بذلك. لدينا ما يكفي من الوقت ، لذلك يمكن القول أنه بحلول الوقت الذي يكون فيه PHP 8 جاهزًا ، سيكون هناك ما يكفي بيننا الذين أتقنوا JIT بما يكفي للعمل ليس أقل كفاءة من اليوم عندما يتعلق الأمر بإصلاح الأخطاء وتطوير PHP.
عندما تحاول ربط هذا بفكرة التعقيد الأصلي لـ JIT ، تذكر أن معظم الوقت الذي نقضيه في تقديم ميزات جديدة يقضي مناقشتها. في أغلب الأحيان ، عند العمل على الميزات وإصلاح الأخطاء ، يستغرق كتابة التعليمات البرمجية دقائق أو ساعات ، والمناقشات تستغرق أسابيع أو أشهر. في حالات نادرة ، يجب كتابة الكود لساعات أو أيام ، لكن حتى ذلك الحين تستمر المناقشات دائمًا لفترة أطول.
هذا هو كل ما أردت أن أقوله.
وبما أننا نتحدث عن الأداء ، أدعو زميلي بافيل مورزاكوف إلى تقديم تقرير يوم 17 مايو في مؤتمر PHP Russia. يعرف باشا كيفية ضغط آخر وحدة معالجة مركزية ثانية من كود PHP!