في الآلات الافتراضية لمتصفحات الويب غالبًا ما يستخدم JIT Compilation... ولكن هل يستطيع أحد أن يشرح لي بدقة وبأسلوب علمي معناه والفارق بينه وبين Ahead-of-time Compilation؟ وكذلك الفارق الدقيق بين Compiler وInterpreter؟
ما المعنى الدقيق لكل من JIT Compilation وAhead-of-time Compilation؟
الوقت هنا (في حرف T في المصطلحين) هو وقت التنفيذ.
المصنف compiler يحول من ملف المصدر باللغة العالية مثل سي إلى ملف تنفيذي بلغة الآلة. يتم حفظ الملف التنفيذي وتنفيذه أي عدد من المرات دون الرجوع لملف المصدر. بمعنى إن قمت بتنفيذ الملف 100 مرة فلن يتم إضاعة أي وقت في قراءة وتفسير الملف المصدر بل إن الملف المصدر في الغالب لا يتم توزيعه مع الملف التنفيذي (يتم التحويل على جهاز المطور مرة واحدة) ومن هنا جاء اسم ahead of time compilation.
المفسر Interpreter يستخدم مع اللغات التفسيرية والتي يتم تداولها غالبا في صورتها المصدرية (وتسمى تلك المصادر مخطوطات أو script كما في javascript ). في كل مرة يتم فيها تنفيذ المخطوطة يتم إعادة إعرابها (تقطيعها وتحليلها ...إلخ) وتنفيذها (سطر فسطر وجزء جزء). قد تختزل بعض اللغات مثل بايثون عمليات الإعراب والتقطيع وذلك من خلال حفظ ملف يسمى بايت كود byte code أو كود الآلة الافتراضية VM وهو باختصار يحتوي إعادة كتابة للبرنامج بلغة غير بشرية أسهل على الحاسوب التعامل معها وهي تكون سلسلة من رموز العمليات OP Codes. عند تنفيذ البرنامج من جديد يتم النظر إلى هذا الملف إن كان تاريخه أحدث من الآخر وإلا يتم إعادة توليده. وإلى هنا لا يوجد عملية ترجمة حقيقية إلى لغة الآلة بمعنى أنك لو نظرت إلى كود أي من تلك المفسرات لن تجد فيها تعليمات بلغة الآلة أو لغة التجميع assembly لكن ستجد عبارة if أو switch تقول إن وجدت رمز عملية الجمع اسحب آخر رقمين في المكدس واجمعهما ثم ادفع الناتج.
لغة جافا كانت تستخدم مفسر حتى ظهر hotspot وهو JIT أي مصنف يعمل في الوقت المناسب على الطاير.
يمكنه تحويل من رموز العلميات بصورة byte code أو virtual machine code إلى لغة الآلة الحقيقية native machine code لكنه لا يحتفظ بها في ملف مستقل بل يفعل ذلك على الطاير وهذا يؤدي إلى تسريع الحلقات التكرارية مقارنة بالمفسر لأنها قبل أول دورة تتحول إلى لغة الآلة وكل الدورات التالية تكون بلغة الآلة.
من الطرائف أن بايثون لديها مصنف اسمه jython يمكنه تحويل برامج بايثون إلى ملفات بلغة الآلة الوهمية الخاصة بجافا .class (وبالتالي .jar) وتنفيذها على JIT الخاص بجافا.
كذلك هناك مفسر للغة بايثون كتاب بلغة بايثون اسمه pypy تم دمج JIT فيه أيضا
لغة lua لديها JIT أيضا
توجد ميزة في مفهوم الـ JIT يُمكن أن تتفوق بها على البرامج التنفيذية والتي سبق ترجمتها، وهو أن يقوم مترجم الـ JIT بترجمة الكود إلى نسخة تنفيذية حسب إمكانات المُعالج، هذه يُمكن أن تجعل برامج الـ Bytecode مثلاً اسرع من الـ binary. وقد قرأتها في الوكيبيديا:
The compilation can be optimized to the targeted CPU and the operating system model where the application runs. For example JIT can choose SSE2 vector CPU instructions when it detects that the CPU supports them. However there is currently no mainstream JIT that implements this. To obtain this level of optimization specificity with a static compiler, one must either compile a binary for each intended platform/architecture, or else include multiple versions of portions of the code within a single binary.
هذه الميزة يُمكن أن يُفيد عند تعدد المعماريات وبعدها عن بعضها في المستقبل.
ماهو رأيك؟
توجد ميزة في مفهوم الـ JIT يُمكن أن تتفوق بها على البرامج التنفيذية
حتى نكون دقيقين يمكن ل JIT أن تتفوق على البرامج المصنفة مسبقا دون تحسين. لكن يمكن للبرامج المصنفة مسبقا استهداف معمارية محددة أو شيء اختياري في معمارية محددة وعندها ليس ل JIT أي أفضلية.
في المثال الذي نقلته هناك إضافة في معالجات إنتل اسمها SSE2 وهي غير موجودة في كل إصدارات معالجات إنتل يمكن استهداف هذه الإضافة عند التصنيف المسبق أيضا. ويمكن تحميل الأجزاء التي تستهدف إضافة معينة في معمارية بعينها من خلال إضافات تحمل في وقت التنفيذ plugins أو so أو dll مثلا تعمل fallback.dll و sse2plugin.dll وهكذا
سأعطيك مثال بسيط الإضافة التالية تستهدف معالجات armv7 والتي فيها الميزة الاختيارية neon ولكل معالج آخر هناك إضافة خاصة به
هذا مثال على التصنيف المسبق ahead of time compiling
طيب ماهو رأيك في هذه الميزة، حيث قرأت أيضاً أن البرامج الثنائية أيضاً يمكن أن تكون متعددة المعماريات بإستخدام ملف يحتوي على profile لعدد من المعالجات، أو شيء من هذا القبيل، لكن هذا سوف يجعل حجم الملف أكبر حيث يحتوي تعليمات لأكثر من معالج.
هل لهذه القضية أهمية في المستقبل؟ مثلاً هل المعماريات في إتجاه أن تكون متشابهة أم تزداد بعداً، أو بمعنى آخر، هل العالم متجه إلى توحيد المعماريات أم زيادتها.
كما أكرر وأول دائما الوقت الضائع في عملية التفسير غالبا مهمل وعنق الزجاجة لم يعد في المفسر فلنقل أنك تعمل لعبة وتريد رسم مشهد مكون من 18 ألف مثلث ثم تعيد رسم المشهد من عدة زوايا.
سابقا كان الوقت الذي سيضيع في التفسير أو التصنيف في حالة JIT مهم جدا وكبير (لنقل أنك تعمل ذلك في جافاسكربت أو بيزك) لكن حاليا كل ما ستفعله داخل اللغة التفسيرية هو إرسال رؤوس المثلثات إلى OpenGL مثلا وهي ستقوم بذلك بأسرع طريقة.
مثلاً هل المعماريات في إتجاه أن تكون متشابهة أم تزداد بعداً، أو بمعنى آخر، هل العالم متجه إلى توحيد المعماريات أم زيادتها.
هو يتوجه نحو تحويد طرق مخاطبتها لكنها تزداد بعدا عن بعضها لكن نخاطبها بطريقة واحدة.
ما أعلمه هو أن هناك مصطلح اسمه الحوسبة غير المتسقة Heterogeneous computing أو الهجينة حيث يتم استخدام معالجات من معماريات مختلفة بل أحيانا خليط من معالجات CPU و GPU.
أحد التقنيات المستخدمة في هذا المجال هي renderscript حيث تصف العمليات التي تريد تنفيذها ثم ترسلها لها الكم الفلكي من البيانات وستتم معالجتها بالطريقة الأنسب والأسرع سواء CPU أو GPU أو كلاهما.
وهناك تقنيات مشابهة مثل CUDA من nvidia وهي متوفرة بأكثر من لغة
وهناك OpenCL
شكرًا للإجابة المفصلة. لدي سؤال آخر: هل الفارق العملي في الأداء واضح جدًا؟ هل هناك أي حِيَل يستخدمها Chrome أو Firefox لجعل JIT Compilation لمخطوطات JavaScript ذات أداء أعلى؟
نعم كروم يستخدم JIT اسمه V8
وفي فايرفوكس هناك SpiderMonkey
وهذه التقنية تحسن الأداء حيث توفر الوقت (الضائع في تفسير الدوال غير المستخدم أو من خلال التفسير مرة واحدة إلى لغة الآلة ثم إعادة استخدامها مجددا عند استدعاء الدالة مجددا مثلا)
ما قصدته هو: هل الفرق العملي بين اللغات التي تُجمع باستخدام Compiler وتلك التي تعتمد JIT بالآلة الافتراضية كبير جدًا؟ لو كتبت برنامجين يؤديان نفس الوظائف بالضبط أحدهما بـJavaScript والآخر بـC++ على سبيل المثال... فهل الفرق ملموس؟
نعم هناك فرق واضح والسرعة هي على الترتيب compiled native machine code ثم JIT virtual machine ثم interpreted لكن هذا الكلام يكون صحيح فقط عند استواء كل العوامل الأخرى مثل التحسين optimization و الاستهداف للإضافات واستخدام نفس الخوارزميات ...إلخ.
في الغالب وعمليا فإن استعمال لغة مثل بايثون أو جافا أو حتى php عملي أكثر ويؤدي الغرض وقد يكون أسرع لأن عنق الزجاجة نادرا ما يكون في الوقت الإضافي الذي تهدره اللغة في التفسير أو التصنيف عند الطلب. فاللغات عالية المستوى مثل بايثون غالبا ما يكون لديها مكتبة قياسية عالية المستوى كتبها خبراء باستعمال أفضل الخوارزميات الموجودة ولأنها عالية المستوى فإن لديها معلومات أكثر ويمكنها عمل تحسين أفضل مثلا في بايثون هناك فئة اسمها المجموعة set تحتفظ بمجموعة من الكائنات دون ترتيب ويمكنها السير عليها لجلبها جميعا (بترتيب عشوائي) أو فحص هل هذا العنصر ينتمي لها أم لا. إن قارنا كود في بايثون يجلب عناصر من ملف مثلا ثم يفحص عدد كبير من المدخلات هل هي ضمن المجموعة أو يقسمها إلى قسمين قسم ضمن المجموعة وقسم خارج المجموعة. فإنه سيكون أسرع من كود سي/سي++ الذي يستخدم الطرق البسيطة وهو أن يحجز منظومة في الذاكرة وظل يدور بين عناصرة في حلقتين داخل بعضهما. طبعا يمكن تطبيق خوارمزية hash table المستخدمة في set بلغة سي/سي++ لكنها ليست جزء من المكتبة القياسية وستضطر لكتابتها وقد لا يمكون التنفيذ الذي قمت به مثاليا أو يستهل منك الكثير من الوقت ....إلخ.
هذا من تجربة عملية فقد كانت ثواب 2 المكتوبة بلغة بايثون أسرع من ثواب 1 المكتوبة بلغة سي مع أني بذلت الكثير من الجهد في تسريع ثواب 1.
لاحظت أن شركة كانونيكال اصبحت تهتم بلغة البايثون، هل يتم استبدال لغة سي في برامج سطح المكتب في أنظمة تشغيل لينكس المختلفة بلغة بايثون
هل برنامج المصحف Othman في لينكس مكتوب ايضاً بلغة بايثون؟
هل برنامج المصحف Othman في لينكس مكتوب ايضاً بلغة بايثون؟
نعم. أغلب برنامج ريدهات/فيدورا/أعجوبة مكتوبة باستعمال بايثون و gtk وهو واحد منها.
هل يتم استبدال لغة سي في برامج سطح المكتب في أنظمة تشغيل لينكس المختلفة بلغة بايثون
نعم لأجل تسريع وتسهيل عملية التطوير. لكن لا يزال الكثير منها مكتوب بلغة سي/سي++. برامج غنوم أغلبها بلغة سي وبرامج كيدي أغلبها بلغة سي++. لكن هناك عدد جيد مكتوب بلغة بايثون خصوصا من أصحاب التوزيعات مثل أدوات التثبيت والإعداد وإدارة الحزم ...إلخ.
JIT Compilation
في النمط العادي : حينما تكتب كود، وتقوم بتحويله الى تطبيق، يحتوى التطبيق على الشيفرة النهائية وهي 0 و 1 ، وهي جاهزة للعمل مباشرة، وتكون اعدادات التطبيق بناء على اعدادات جهاز المبرمج وليس المستخدم ، مثلا نوع المعالج وكارت الشاشة والذاكرة ونوع نظام التشغيل
الترجمة على الفور: لا يحتوي التطبيق على 0 و 1، بل يحتوي على كود لحظي اعقد نوعا ما من الكود الاساسي، وحينما تشغل التطبيق على الكمبيوتر ، يقوم برنامج صغير بقراءة الكود اللحظي وتحويله الى 0 و 1 ، بعد ان يقوم بفحص النظام الحالي، لكي يحصل البرنامج على افضل كفاءة
التعليقات