سؤال

ما هو قفل مترجم عالمي ولماذا المشكلة؟

تم إجراء الكثير من الضوضاء حول إزالة جيل من بيثون، وأود أن أفهم لماذا هذا مهم جدا. لم أكتب أبدا مترجم ولا مترجم بنفسي، لذلك لا تكون مقتصد مع التفاصيل، ربما سأحتاج إليها لفهمها.

هل كانت مفيدة؟

المحلول

يهدف GIL في Python إلى تسلسل الوصول إلى Interperter Internals من مؤشرات ترابط مختلفة. على الأنظمة متعددة النواة، فهذا يعني أن المواضيع المتعددة لا يمكن أن تستخدم بشكل فعال من النوى المتعددة. (إذا لم يقود GIL إلى هذه المشكلة، فلن يهتم معظم الأشخاص بالجليل - إنه يتم طرحه إلا كمسألة بسبب انتشار النظم الأساسية المتزايدة.) إذا كنت ترغب في فهمه بالتفصيل، يمكنك عرض هذا الفيديو أو انظر إلى هذه المجموعة من الشرائح. وبعد قد يكون الكثير من المعلومات، ولكن بعد ذلك طلبت التفاصيل :-)

لاحظ أن Gil Gil Python هو حقا مشكلة بالنسبة ل Cpython، والتنفيذ المرجعي. جيثون والنيرانثون ليس لديهم جيل. كمطور بيثون، لا تأتي عموما عبر GIL إلا إذا كنت تكتب ملحق C. تحتاج كتاب تمديد C إلى إطلاق GIL عندما تقوم ملحقاتهم بحظر I / O، بحيث يحصل مؤشرات الترابط الأخرى في عملية Python على فرصة التشغيل.

نصائح أخرى

لنفترض أن لديك مؤشرات ترابط متعددة لا حقا المس بيانات بعضها البعض. يجب أن تنفذ تلك بشكل مستقل قدر الإمكان. إذا كان لديك "قفل عالمي"، فأنت بحاجة إلى الحصول عليها من أجل (قل) استدعاء وظيفة، يمكن أن ينتهي بك الأمر كقاتجة. يمكنك أن تستفيد الكثير من الاستفادة من وجود خيوط متعددة في المقام الأول.

لوضعها في تشبيه عالمي حقيقي: تخيل 100 مطورين يعملون في شركة مع قدح قهوة واحدة فقط. معظم المطورين سيقضون وقتهم في انتظار القهوة بدلا من الترميز.

لا شيء من هذا هو python الخاص - لا أعرف تفاصيل ما تحتاجه بيثون جيل في المقام الأول. ومع ذلك، نأمل أن تعطى لك فكرة أفضل عن المفهوم العام.

دعونا نفهم أولا ما يوفره بيثون جيل:

يتم تنفيذ أي عملية / تعليمات في المترجم. Gil يضمن أن المترجم الذي يحتفظ به موضوع واحد في لحظة معينة من الوقت. وبعد وبرنامج Python الخاص بك مع مؤشرات الترابط متعددة في مترجم واحد. في أي لحظة معينة من الوقت، يحتفظ هذا المترجم بموضوع واحد. هذا يعني أن الخيط الوحيد الذي يحمل المترجم هو ادارة في أي لحظة من الوقت.

الآن لماذا هذه مشكلة:

يمكن أن يكون جهازك وجود نوى / معالجات متعددة. واسمح للنوى المتعددة مؤشرات الترابط متعددة الوقت ذاته أي المواضيع المتعددة يمكن أن تنفذ في أي لحظة معينة من الوقت.وبعد ولكن نظرا لأن المترجم الذي يحتفظ به موضوع واحد، فإن المواضيع الأخرى لا تفعل أي شيء على الرغم من أن لديهم إمكانية الوصول إلى جوهر. لذلك، لا تحصل على أي ميزة مقدمة من النوى المتعددة لأنه في أي لحظة واحدة فقط جوهر واحد، وهو الأساسي الذي يستخدمه الخيط الذي يحمل حاليا المترجم، يتم استخدامه. لذلك، سيستغرق برنامجك طالما يتم تنفيذه كما لو كان برنامجا مترابطا واحدا.

ومع ذلك، فإن حظر العمليات المحتملة أو الجري الطويلة، مثل I / O ومعالجة الصور وعدد Numpy Truncing، يحدث خارج GIL. مأخوذ من هنا. وبعد لذلك بالنسبة لهذه العمليات، ستظل عملية متعددة المراقبين أسرع من عملية خيوط واحدة على الرغم من وجود جيل. لذلك، جيل ليس دائما عنق الزجاجة.

تحرير: جيل هو تفاصيل تنفيذ CPETHON. لم يكن لدى Ironpython و Jython GIL، لذلك يجب أن يكون برنامج متعدد مؤشرات الترابط حقا ممكنا فيه، فكر في أنني لم أستخدم مطلقا pypy و Jython وغير متأكد من هذا.

لا تسمح بيثون بخيبة الترابط متعددة المعنى الحقيقي للكلمة. يحتوي على حزمة متعددة الخيوط ولكن إذا كنت ترغب في تخطيط متعدد الترابط لتسريع التعليمات البرمجية الخاصة بك، فمن عادة ليست فكرة جيدة لاستخدامها. Python لديه بناء يسمى قفل المترجم العالمي (GIL).

https://www.youtube.com/watch؟v=ph374fjqfpe.

تتأكد GIL من تنفيذ واحد فقط من "مؤشرات الترابط" الخاصة بك في أي وقت واحد. يكتسب الخيط GIL، يقوم بعمل صغير، ثم يمر GIL على الموضوع التالي. يحدث هذا بسرعة كبيرة حتى لا يبدو أن مؤشرات الترابط الخاصة بك تنفذ بالتوازي، لكنها مجرد اتخاذها فقط باستخدام نفس CPU Core. كل هذا يمر gil يضيف النفقات العامة إلى التنفيذ. هذا يعني أنه إذا كنت ترغب في تشغيل التعليمات البرمجية بشكل أسرع، فغالبا ما تكون استخدام حزمة الخيوط في كثير من الأحيان ليست فكرة جيدة.

هناك أسباب لاستخدام حزمة خيوط بيثون. إذا كنت ترغب في تشغيل بعض الأشياء في وقت واحد، والكفاءة ليست مصدر قلق، فهي جيدة تماما ومريحة تماما. أو إذا كنت تقوم بتشغيل التعليمات البرمجية التي تحتاج إلى الانتظار لشيء ما (مثل بعض IO)، فيمكنه تحقيق الكثير من المعنى. لكن مكتبة الخيوط لن تتيح لك استخدام النوى CPU إضافية.

يمكن الاستعانة بمصادر خارجية متعددة الخيوط في نظام التشغيل (عن طريق القيام بعمل متعدد)، بعض التطبيق الخارجي الذي يستدعي رمز بيثون الخاص بك (على سبيل المثال، شرارة أو هيدوب)، أو بعض الكود الذي يدعو رمز بيثون الخاص بك (على سبيل المثال: هل يمكن أن يكون لديك بيثون الخاص بك Code استدعاء وظيفة C التي تقوم بالأشياء متعددة الخيوط باهظة الثمن).

كلما كان لديك مواضيعان الوصول إلى نفس المتغير لديك مشكلة. في C ++ على سبيل المثال، فإن طريقة تجنب المشكلة هي تحديد بعض قفل Mutex لمنع مؤشر ترابطين، دعنا نقول، أدخل STERTER لكائن في نفس الوقت.

تعدد مؤشرات الترددات المتعددة في Python، ولكن لا يمكن تنفيذ مؤشرات ترابطين في نفس الوقت في دققبيا من تعليمات Python. يخطئ الخيط هو الحصول على قفل عالمي يسمى جيل.

هذا يعني أنه إذا بدأت في كتابة بعض التعليمات البرمجية متعددة المراحل للاستفادة من المعالج متعدد الصور الخاص بك، فلن يتحسن أدائك. يتكون الحلول المعتاد من الذهاب إلى المعالجات.

لاحظ أنه من الممكن إطلاق GIL إذا كنت داخل طريقة كتبتها في C على سبيل المثال.

إن استخدام gil ليس متأصل في ثعبان ولكن لبعض المترجم الخاص به، بما في ذلك cpephon الأكثر شيوعا. (# للتطبيق، انظر التعليق)

لا تزال مشكلة GIL صالحة في Python 3000.

وثائق بيثون 3.7.

أود أيضا أن أبرز اقتباس التالي من بيثون threading توثيق:

تفاصيل تنفيذ CPYTHON: في CPYTHON، بسبب قفل مترجم فوري العالمي، يمكن لخيط واحد فقط تنفيذ رمز Python مرة واحدة (على الرغم من أن بعض المكتبات الموجهة نحو الأداء قد تتغلب على هذا القيد). إذا كنت ترغب في تقديم طلبك بشكل أفضل للموارد الحسابية للآلات متعددة النواة، فأنت ننصح باستخدامه multiprocessing أو concurrent.futures.ProcessPoolExecutor. وبعد ومع ذلك، لا يزال الخيوط لا يزال نموذجا مناسبا إذا كنت ترغب في تشغيل مهام متعددة I / O متعددة في وقت واحد.

هذه الروابط إلى دخول المسرد global interpreter lock الذي يفسر أن Gil يعني أن التوازي الخيوط في بيثون غير مناسب مهام وحدة المعالجة المركزية المنفصلة:

الآلية المستخدمة من قبل مترجم CPYTHON لضمان أن مؤشر ترابط واحد فقط ينفذ Python bytecode في وقت واحد. هذا يبسط تنفيذ CPYTHON من خلال جعل نموذج الكائن (بما في ذلك الأنواع المدمجة النقدية مثل DCT) آمنة ضمنيا ضد الوصول المتزامن. إن قفل المترجم بالكامل يجعل من السهل أن يكون مترجم الترابط متعدد الخيوط، على حساب الكثير من التوازي الذي يوفره آلات متعددة المعالجات.

ومع ذلك، تم تصميم بعض وحدات الامتداد، إما قياسي أو طرف ثالث، حتى تحرير GIL عند القيام بمهام مكثفة حسابية مثل الضغط أو التجزئة. أيضا، يتم عرض جيل دائما عند القيام بإدخال / س.

الجهود السابقة لإنشاء مترجم "مترابط خالص" (الذي يقوم بإغلاق البيانات المشتركة بتصبيح أدق بكثير) لم ينجح لأن الأداء عانى في حالة المعالج الفردي المشترك. ويعتقد أن التغلب على قضية الأداء هذه من شأنه أن يجعل التنفيذ أكثر تعقيدا وبالتالي أكثر تكلفة للحفاظ عليها.

هذا الاقتباس يعني أيضا أن المخابرات وهكذا هي أيضا مهمة متغيرة هي أيضا خزانة آمنة كتفاصيل تنفيذ CPYTHON:

بعد ذلك، مستندات ل multiprocessing صفقة اشرح كيف يتغلب على GIL عن طريق عملية التفريخ أثناء تعريض واجهة مماثلة لتلك التي threading:

Metchrocessing هي حزمة تدعم عمليات التفريخ باستخدام API مشابهة لوحدة الخيوط. تقدم حزمة MultipRoccessing التزامن المحلي والبعيد، جنبا إلى جنب بشكل فعال - قم بإخلاص قفل الفراش العالمي باستخدام الإعدادات الفرعية بدلا من المواضيع. نظرا لهذا، تسمح وحدة MultipRoccessing للمبرمج بالاستفادة بالكامل من معالجات متعددة على جهاز معين. يعمل على كل من يونيكس والنوافذ.

و ال مستندات ل concurrent.futures.ProcessPoolExecutor اشرح أنه يستخدم multiprocessing كخلفية:

Class ProcessPoolExecutor هي فئة فرعية منفذية تستخدم مجموعة من العمليات لتنفيذ المكالمات بشكل غير متزامن. يستخدم ProcessPoolexecutor الوحدة النمطية متعددة المعالجات، والتي تتيح لها خطوة جانبية قفل المترجم العالمي ولكنها تعني أيضا أنه يمكن تنفيذ الكائنات المقابلة فقط وإرجاعها.

والتي ينبغي أن يتناقض مع الطبقة الأساسية الأخرى ThreadPoolExecutor الذي - التي يستخدم المواضيع بدلا من العمليات

ThreadPoolExecutor هو فئة فرعية منفذية تستخدم مجموعة من الخيوط لتنفيذ المكالمات بشكل غير متزامن.

التي نستنتج ذلك ThreadPoolExecutor مناسبة فقط لمهام I / O المرتبطة، في حين ProcessPoolExecutor يمكن أيضا التعامل مع المهام المنفصلة وحدة المعالجة المركزية.

يسأل السؤال التالي لماذا موجود جيل في المقام الأول: لماذا قفل المترجم العالمي؟

عملية VS تجارب الموضوع

في multiprocessing vs الخيوط بيثون لقد قمت بإجراء تحليل تجريبي للعملية مقابل المواضيع في بيثون.

معاينة سريعة للنتائج:

enter image description here

لماذا يستخدم Python (CpeThon وغيرها) GIL

من http://wiki.python.org/moin/globalinterpererlock.

في CpeThon، قفل المترجم العالمي، أو GIL، هو Mutex يمنع مؤشرات الترابط الأصلية متعددة من تنفيذ Python bytecodes مرة واحدة. هذا القفل ضروري بشكل أساسي لأن إدارة ذاكرة Cpython ليست آمنة للخيط.

كيفية إزالته من بيثون؟

مثل LUA، ربما يمكن أن يبدأ بيثون متعددة VM، لكن بيثون لا يفعل ذلك، أعتقد أنه يجب أن يكون هناك بعض الأسباب الأخرى.

في Numppy أو بعض مكتبة Python الممتدة الأخرى، في بعض الأحيان، فإن إطلاق GIL إلى مؤشرات الترابط الأخرى قد يعزز كفاءة البرنامج بأكمله.

أريد أن أشارك مثالا من كتاب متعدد المراحل للتأثيرات المرئية. لذلك هنا هو وضع قفل ميت كلاسيكي

static void MyCallback(const Context &context){
Auto<Lock> lock(GetMyMutexFromContext(context));
...
EvalMyPythonString(str); //A function that takes the GIL
...    
}

الآن النظر في الأحداث في التسلسل الناتجة عن قفل ميت.

╔═══╦════════════════════════════════════════╦══════════════════════════════════════╗
║   ║ Main Thread                            ║ Other Thread                         ║
╠═══╬════════════════════════════════════════╬══════════════════════════════════════╣
║ 1 ║ Python Command acquires GIL            ║ Work started                         ║
║ 2 ║ Computation requested                  ║ MyCallback runs and acquires MyMutex ║
║ 3 ║                                        ║ MyCallback now waits for GIL         ║
║ 4 ║ MyCallback runs and waits for MyMutex  ║ waiting for GIL                      ║
╚═══╩════════════════════════════════════════╩══════════════════════════════════════╝
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top