الحفاظ على استجابة واجهات المستخدم الرسومية أثناء المهام طويلة الأمد

StackOverflow https://stackoverflow.com/questions/148963

  •  02-07-2019
  •  | 
  •  

سؤال

يعد الحفاظ على استجابة واجهة المستخدم الرسومية أثناء قيام التطبيق ببعض عمليات المعالجة الثقيلة لوحدة المعالجة المركزية أحد تحديات برمجة واجهة المستخدم الرسومية الفعالة.

هنا مناقشة جيدة حول كيفية القيام بذلك في wxPython.لتلخيص، هناك 3 طرق:

  1. استخدام المواضيع
  2. استخدم wxYield
  3. قم بتقطيع العمل وتنفيذه في معالج الأحداث IDLE

الطريقة التي لديها أنت وجدت أن تكون الأكثر فعالية؟نرحب أيضًا بالتقنيات من أطر العمل الأخرى (مثل Qt أو GTK أو Windows API).

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

المحلول

الخيوط.هذا ما أسعى إليه دائمًا لأنه يمكنك القيام بذلك في كل إطار عمل تحتاجه.

وبمجرد أن تعتاد على المعالجة المتعددة الخيوط والمعالجة المتوازية في لغة/إطار عمل واحد، تصبح جيدًا في جميع الأطر.

نصائح أخرى

المواضيع بالتأكيد.لماذا؟المستقبل متعدد النواة.تحتوي أي وحدة معالجة مركزية جديدة تقريبًا على أكثر من نواة واحدة، أو إذا كانت تحتوي على نواة واحدة فقط، فقد تدعم تقنية Hyperthreading وبالتالي تتظاهر بأنها تحتوي على أكثر من نواة واحدة.للاستفادة بشكل فعال من وحدات المعالجة المركزية متعددة النواة (وتخطط شركة Intel للوصول إلى 32 مركزًا في المستقبل غير البعيد)، تحتاج إلى عدة سلاسل عمليات.إذا قمت بتشغيل الكل في مؤشر ترابط رئيسي واحد (عادةً ما يكون مؤشر ترابط واجهة المستخدم هو الخيط الرئيسي)، فسيكون لدى المستخدمين وحدات معالجة مركزية تحتوي على 8 و16 و32 نواة في اليوم الواحد ولن يستخدم تطبيقك أبدًا أكثر من واحد منها، IOW يعمل بشكل أبطأ بكثير مما يمكن تشغيله.

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

في الواقع، تخطط شركات مثل Apple وMicrosoft بالفعل لكيفية جعل واجهات المستخدم الأكثر ترابطًا الخاصة بها هي نفسها متعددة الخيوط.حتى مع النهج الموضح أعلاه، قد تواجه يومًا ما موقفًا مفاده أن واجهة المستخدم هي عنق الزجاجة بحد ذاتها.يمكن لعمليات الخلفية معالجة البيانات بشكل أسرع بكثير مما تستطيع واجهة المستخدم تقديمه للمستخدم أو مطالبة المستخدم بالإدخال.اليوم، أصبحت العديد من أطر عمل واجهة المستخدم آمنة قليلًا لسلاسل العمليات، والعديد منها غير آمن لسلاسل العمليات على الإطلاق، لكن هذا سيتغير.المعالجة التسلسلية (القيام بمهمة واحدة تلو الأخرى) هي تصميم يحتضر، والمعالجة المتوازية (القيام بالعديد من المهام في وقت واحد) هي المكان الذي يتجه إليه المستقبل.مجرد إلقاء نظرة على محولات الرسومات.حتى أحدث بطاقة NVidia لديها أداء يرثى له، إذا نظرت إلى سرعة المعالجة بالميغاهيرتز/جيجاهرتز لوحدة معالجة الرسومات وحدها.كيف يمكن التغلب على حماقة وحدات المعالجة المركزية عندما يتعلق الأمر بالحسابات ثلاثية الأبعاد؟بسيط:بدلاً من حساب نقطة مضلع واحدة أو بكسل نسيج واحد تلو الآخر، فإنه يحسب العديد منها بالتوازي (في الواقع مجموعة كاملة في نفس الوقت) وبهذه الطريقة يصل إلى إنتاجية لا تزال تجعل وحدات المعالجة المركزية تبكي.على سبيل المثاليحتوي ATI X1900 (على سبيل المثال المنافس أيضًا) على 48 وحدة تظليل!

أظن delayedresult هو ما تبحث عنه:

http://www.wxpython.org/docs/api/wx.lib.delayedresult-module.html

راجع العرض التوضيحي لـ wxpython للحصول على مثال.

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

المواضيع - دعنا نستخدم طريقة عرض بسيطة من طبقة (واجهة المستخدم الرسومية ، منطق التطبيق).

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

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

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

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

يحرر - نسيت أن أذكر أن جمال ذلك هو أنه من الممكن فصل منطق التطبيق تمامًا عن كود واجهة المستخدم الرسومية.تساعد الوحدة النمطية إذا قررت استخدام إطار عمل مختلف أو استخدام توفير إصدار سطر أوامر من التطبيق.للقيام بذلك، ستحتاج إلى مرسل حدث متوسط ​​(مستوى التطبيق -> واجهة المستخدم الرسومية) يتم تنفيذه بواسطة طبقة واجهة المستخدم الرسومية.

العمل مع Qt/C++ لـ Win32.

نقوم بتقسيم وحدات العمل الرئيسية إلى عمليات مختلفة.تعمل واجهة المستخدم الرسومية كعملية منفصلة وتكون قادرة على التحكم/تلقي البيانات من العمليات "العاملة" حسب الحاجة.يعمل بشكل جيد في عالم اليوم متعدد النواة.

لا تنطبق هذه الإجابة على سؤال OP بخصوص Python، ولكنها أكثر من مجرد استجابة وصفية.

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

هناك مشكلة أخرى في استخدام سلاسل الرسائل في BREW وهي أنها لا تقوم بتنظيف كائنات مكدس C++، لذلك من السهل جدًا تسريب الذاكرة إذا قمت ببساطة بقتل مؤشر الترابط.

أستخدم سلاسل الرسائل حتى لا يتم حظر حلقة الحدث الرئيسية لواجهة المستخدم الرسومية أبدًا.

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

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

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

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top