التنفيذ الديناميكي

التنفيذ الديناميكي هو ميزة في Bazel منذ الإصدار 0.21، حيث يبدأ التنفيذ المحلي وعن بُعد للإجراء نفسه بالتوازي، باستخدام مخرجات الفرع الأول الذي ينتهي مع إلغاء الفرع الآخر. تجمع هذه الأداة بين قدرة التنفيذ و/أو ذاكرة التخزين المؤقت المشتركة الكبيرة لنظام التصميم عن بُعد مع وقت الاستجابة المنخفض للتنفيذ المحلي، ما يوفّر أفضل ما في كلا الإصدارَين لكل من الإصدارات النظيفة والمتزايدة على حدٍ سواء.

توضّح هذه الصفحة كيفية تفعيل التنفيذ الديناميكي وضبطه وتصحيح أخطائه. إذا كنت قد أعدّدت التنفيذ المحلي وعن بُعد وكنت تحاول ضبط إعدادات Bazel لتحسين الأداء، هذه الصفحة مناسبة لك. إذا لم يسبق لك إعداد التنفيذ عن بُعد، انتقِل إلى نظرة عامة على التنفيذ عن بُعد في Bazel.

هل تريد تفعيل التنفيذ الديناميكي؟

تعتبر وحدة التنفيذ الديناميكي جزءًا من Bazel، ولكن للاستفادة من التنفيذ الديناميكي، يجب أن تكون قادرًا على التجميع محليًا وعن بُعد من إعداد Bazel نفسه.

لتفعيل وحدة التنفيذ الديناميكية، مرِّر علامة --internal_spawn_scheduler إلى Bazel. يؤدي ذلك إلى إضافة استراتيجية تنفيذ جديدة باسم dynamic. يمكنك الآن استخدام هذه الاستراتيجية كاستراتيجية للتذكّرات التي تريد تشغيلها ديناميكيًا، مثل --strategy=Javac=dynamic. اطّلِع على القسم التالي للتعرّف على كيفية اختيار الرموز اللغوية لتفعيل التنفيذ الديناميكي لها.

بالنسبة إلى أي حزمة تذكارية تستخدم الاستراتيجية الديناميكية، يتم أخذ استراتيجيات التنفيذ عن بُعد من العلامة --dynamic_remote_strategy والاستراتيجيات المحلية من العلامة --dynamic_local_strategy. عند تمرير السياسة --dynamic_local_strategy=worker,sandboxed، يتم ضبط الإعداد التلقائي للفرع المحلي للتنفيذ الديناميكي لتجربته مع العمّال أو تنفيذ وضع الحماية في وضع الحماية بهذا الطلب. ويؤدي اجتياز --dynamic_local_strategy=Javac=worker إلى تجاوز الإعداد التلقائي لتذكّر لغة Javac فقط. يعمل الإصدار البعيد بالطريقة نفسها. يمكن تحديد كلتا العلامتين عدة مرات. إذا تعذّر تنفيذ إجراء محليًا، يتم تنفيذه عن بُعد كالمعتاد، والعكس صحيح.

إذا كان النظام البعيد يتضمن ذاكرة تخزين مؤقتة، تضيف العلامة --local_execution_delay مهلة تأخير بالملي ثانية إلى التنفيذ المحلي بعد أن يشير النظام البعيد إلى نتيجة ذاكرة تخزين مؤقت. ويؤدي ذلك إلى تجنُّب تنفيذ التنفيذ المحلي عندما يُحتمل أن ينتج عن ذلك المزيد من نتائج ذاكرة التخزين المؤقت. القيمة التلقائية هي 1, 000 ملي ثانية، ولكن يجب ضبطها لتكون أطول قليلاً من نتائج ذاكرة التخزين المؤقت التي تستغرقها عادةً. يعتمد الوقت الفعلي على كل من النظام البعيد والمدة التي تستغرقها الرحلة ذهابًا وإيابًا. وعادةً ما تكون القيمة هي نفسها لجميع مستخدمي نظام بعيد، ما لم يكن بعضهم كافيًا لإضافة وقت استجابة ذهاب وعودة. يمكنك استخدام ميزات تحديد ملفات Bazel الوصفية للاطّلاع على المدة التي تستغرقها نتائج ذاكرة التخزين المؤقت المعتادة.

يمكن استخدام التنفيذ الديناميكي مع استراتيجية وضع الحماية المحلية، بالإضافة إلى العاملين الدائمين. سيعمل العاملون الدائمون تلقائيًا مع وضع الحماية عند الاستخدام مع التنفيذ الديناميكي، ولا يمكنهم استخدام العمّال المتعددين. في أنظمة الدروين وWindows، يمكن أن تكون استراتيجية وضع الحماية بطيئة، ويمكنك اجتياز --reuse_sandbox_directories لتقليل النفقات الناتجة عن إنشاء وضع الحماية على هذه الأنظمة.

ويمكن أيضًا تنفيذ التنفيذ الديناميكي باستخدام الاستراتيجية standalone، ولكن نظرًا لأنّ الاستراتيجية standalone يجب أن تقفل قفل الإخراج عندما يبدأ تنفيذها، فإنّ ذلك يمنع الاستراتيجية البعيدة من الانتهاء أولاً. تساعد العلامة --experimental_local_lockfree_output في حل هذه المشكلة من خلال السماح للتنفيذ المحلي بالكتابة مباشرةً إلى الإخراج، ولكن يتم إلغاء عملية التنفيذ عن بُعد، في حال انتهت هذه العملية أولاً.

إذا اكتمل أحد فروع التنفيذ الديناميكي أولاً ولكنه تعذّر تنفيذه، سيتعذّر تنفيذ الإجراء بالكامل. وهذا خيار مقصود لمنع الاختلافات بين تنفيذ الإجراء المحلي والبعيد.

لمزيد من المعلومات الأساسية حول آلية التنفيذ الديناميكي وعمليات القفل، يُرجى الاطّلاع على قناة Julio Merino's الممتازة مشاركات المدوّنة.

متى يجب استخدام التنفيذ الديناميكي؟

يتطلب التنفيذ الديناميكي شكلاً من أشكال نظام التنفيذ عن بُعد. لا يمكن حاليًا استخدام نظام تحكم عن بُعد فقط لذاكرة التخزين المؤقت، حيث إن اعتبار ذاكرة التخزين المؤقت المفقودة سيتم اعتباره إجراءً فاشلًا.

ليست كل أنواع الإجراءات مناسبة للتنفيذ عن بُعد. إنّ أفضل المرشحين هم بطبيعتهم بشكل أسرع محليًا، على سبيل المثال، من خلال استخدام العاملين الدائمين، أو أولئك الذين يعملون بسرعة كبيرة بما يكفي لمواكبة وقت التنفيذ عن بُعد. ولأنّ كل إجراء يتم تنفيذه محليًا يقفل قدرًا كبيرًا من موارد وحدة المعالجة المركزية (CPU) والذاكرة، إنّ تنفيذ الإجراءات التي لا تندرج ضمن هذه الفئات يؤدي فقط إلى تأخير تنفيذ الإجراءات التي تنفّذها.

اعتبارًا من الإصدار 5.0.0-pre.20210708.4، يتضمّن تحديد ملفات الأداء بيانات عن تنفيذ العاملين، بما في ذلك الوقت المستغرق في إنهاء طلب العمل بعد خسارة سباق التنفيذ الديناميكي. إذا لاحظت أن سلاسل محادثات التنفيذ الديناميكي تقضي وقتًا كبيرًا في الحصول على الموارد، أو الكثير من الوقت في async-worker-finish، قد تكون لديك بعض الإجراءات المحلية البطيئة التي تؤخِّر سلاسل محادثات العاملين.

تحليل البيانات من خلال أداء ضعيف في التنفيذ الديناميكي

في الملف الشخصي أعلاه الذي يستخدم 8 عاملين في Javac، نلاحظ أن العديد من العاملين في Javac قد فقدوا السباقات ويقومون بإنهاء أعمالهم على سلاسل محادثات async-worker-finish. ويعود السبب في ذلك إلى استغراق أحد الموظفين في العمل في الذاكرة، ما يؤدي إلى استهلاك موارد كافية.

تحليل البيانات من خلال تحسين أداء التنفيذ الديناميكي

عندما يتم تشغيل Javac فقط بالتنفيذ الديناميكي، ينتهي الأمر بحوالي نصف العاملين فقط في بداية السباقات بعد بدء عملهم.

تم إيقاف علامة --experimental_spawn_scheduler المقترَحة نهائيًا. ويتم تفعيل ميزة "التنفيذ الديناميكي" وضبط dynamic كاستراتيجية تلقائية لجميع عمليات الذاكرة، ما قد يؤدي غالبًا إلى حدوث هذه الأنواع من المشاكل.

تحديد المشاكل وحلّها

قد تكون مشاكل التنفيذ الديناميكي دقيقة ومعقّدة في تصحيح الأخطاء، لأنّها لا يمكن أن تظهر إلا ضمن بعض التركيبات المحدّدة للتنفيذ المحلي وعن بُعد. تضيف --debug_spawn_scheduler الناتج الإضافي من نظام التنفيذ الديناميكي الذي يمكن أن يساعد في تصحيح هذه المشاكل. يمكنك أيضًا ضبط علامة --local_execution_delay وعدد المهام عن بُعد مقابل الوظائف المحلية لتسهيل إعادة إظهار المشاكل.

إذا كنت تواجه مشاكل في التنفيذ الديناميكي باستخدام استراتيجية standalone، جرِّب التشغيل بدون --experimental_local_lockfree_output، أو شغِّل إجراءاتك المحلية في وضع الحماية. قد يؤدي ذلك إلى إبطاء الإصدار قليلاً (انظر أعلاه إذا كنت تستخدم نظام التشغيل Mac أو Windows)، ولكن مع إزالة بعض الأسباب المحتملة لتعذُّر إتمام الإصدار.