متى يتم استخدام تجمع مؤشرات الترابط في C#؟[مغلق]

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

  •  02-07-2019
  •  | 
  •  

سؤال

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

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

المحلول

إذا كان لديك الكثير من المهام المنطقية التي تتطلب معالجة مستمرة وتريد أن يتم ذلك بالتوازي، فاستخدم برنامج الجدولة+pool.

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

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

عادةً ما يتكون المجمع من خيطين لكل معالج (من المحتمل أن يكون 4 في الوقت الحاضر)، ومع ذلك يمكنك إعداد كمية الخيوط التي تريدها، إذا كنت تعرف عدد الخيوط التي تحتاجها.

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

نصائح أخرى

أود أن أقترح عليك استخدام تجمع مؤشرات الترابط في C# لنفس الأسباب مثل أي لغة أخرى.

عندما تريد تحديد عدد سلاسل الرسائل قيد التشغيل أو لا ترغب في تحمل تكاليف إنشائها وتدميرها، استخدم تجمع سلاسل الرسائل.

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

وإلا فإنك تقضي الجزء الأكبر من وقتك في إنشاء المواضيع وتدميرها بدلاً من مجرد القيام بالعمل الذي تهدف إلى القيام به.

فيما يلي ملخص لطيف لتجمع سلاسل الرسائل في .Net: http://blogs.msdn.com/pedram/archive/2007/08/05/dedicated-thread-or-a-threadpool-thread.aspx

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

أوصي بشدة بقراءة هذا الكتاب الإلكتروني المجاني:الخيوط في C# لجوزيف البحري

على الأقل اقرأ قسم "البدء".يوفر الكتاب الإلكتروني مقدمة رائعة ويتضمن ثروة من معلومات الخيوط المتقدمة أيضًا.

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

  • المكتبة الموازية للمهمة (.NET Framework 4.0)
  • ThreadPool.QueueUserWorkItem
  • المندوبون غير المتزامنين
  • تطبيقBackgroundWorker

يشرح هذا الكتاب الإلكتروني كل هذه الأمور وينصح بموعد استخدامها مقابل استخدامها.إنشاء الموضوع الخاص بك.

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

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

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

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

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

ملحوظة:لقد سألت عن استخدام مؤشر ترابط تجمع مؤشرات الترابط لتنزيل البيانات أو إجراء إدخال/إخراج القرص.لا يجب عليك استخدام مؤشر ترابط تجمع مؤشرات الترابط لهذا (للأسباب التي ذكرتها أعلاه).بدلاً من ذلك، استخدم الإدخال/الإخراج غير المتزامن (المعروف أيضًا باسم طريقتي BeginXX وEndXX).ل FileStream ممكن حدوثه BeginRead و EndReadHttpWebRequest ممكن حدوثه BeginGetResponse و EndGetResponse.إنها أكثر تعقيدًا في الاستخدام، ولكنها الطريقة الصحيحة لإجراء عمليات الإدخال/الإخراج متعددة الخيوط.

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

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

يمكن أن يكون لاستخدام تجمع مؤشرات الترابط تأثيرات دقيقة - تستخدم بعض أجهزة ضبط الوقت في .NET مؤشرات ترابط تجمع مؤشرات الترابط ولن يتم تشغيلها، على سبيل المثال.

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

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

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

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

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

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

والآن مع قليل من الواقعية:

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

لذا فإن الأمر الأكثر أهمية هو مناقشة ما هو سهل البرمجة.

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

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

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

هناك طريقة سهلة للمقارنة وهي بدء تشغيل 512 موضوعًا و512 مهمة و512 موضوعًا في ThreadPool.ستجد تأخيرًا في البداية مع المواضيع (وبالتالي، لماذا تكتب تجمع سلاسل الرسائل)، ولكن سيتم تشغيل جميع سلاسل الرسائل البالغ عددها 512 في بضع ثوانٍ بينما تستغرق المهام وسلاسل .NET ThreadPool ما يصل إلى بضع دقائق لبدء التشغيل.

فيما يلي نتائج هذا الاختبار (i5 رباعي النواة مع 16 جيجابايت من ذاكرة الوصول العشوائي)، مع إعطاء كل 30 ثانية للتشغيل.يقوم الكود الذي تم تنفيذه بتنفيذ إدخال/إخراج ملف بسيط على محرك أقراص SSD.

نتائج الإختبار

تعتبر تجمعات مؤشرات الترابط رائعة عندما يكون لديك مهام أكثر لمعالجة من سلاسل الرسائل المتوفرة.

يمكنك إضافة كافة المهام إلى تجمع سلاسل الرسائل وتحديد الحد الأقصى لعدد سلاسل الرسائل التي يمكن تشغيلها في وقت معين.

الدفع هذا الصفحة على MSDN:http://msdn.microsoft.com/en-us/library/3dasc8as(VS.80).aspx

استخدم دائمًا تجمع مؤشرات الترابط إذا استطعت، واعمل على أعلى مستوى ممكن من التجريد.تخفي تجمعات المواضيع إنشاء المواضيع وتدميرها، وهذا عادة ما يكون أمرًا جيدًا!

يمكنك في أغلب الأحيان استخدام التجمع لتجنب العملية الباهظة الثمن لإنشاء سلسلة الرسائل.

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

لا تنس التحقق من عامل الخلفية.

أجد في الكثير من المواقف أنه يمنحني ما أريد دون الحاجة إلى رفع الأثقال.

هتافات.

عادةً ما أستخدم Threadpool عندما أحتاج إلى القيام بشيء ما في موضوع آخر ولا أهتم حقًا عند تشغيله أو انتهائه.شيء مثل التسجيل أو ربما حتى تنزيل ملف في الخلفية (على الرغم من وجود طرق أفضل للقيام بهذا النمط غير المتزامن).أستخدم الخيط الخاص بي عندما أحتاج إلى مزيد من التحكم.ما وجدته أيضًا هو أن استخدام قائمة انتظار Threadsafe (اختراق القائمة الخاصة بك) لتخزين "كائنات الأوامر" يعد أمرًا رائعًا عندما يكون لدي أوامر متعددة أحتاج إلى العمل عليها في> مؤشر ترابط واحد.لذلك يمكنك تقسيم ملف Xml ووضع كل عنصر في قائمة انتظار ومن ثم يكون لديك عدة سلاسل رسائل تعمل على إجراء بعض المعالجة على هذه العناصر.لقد كتبت طريقة قائمة الانتظار هذه في uni (VB.net!) والتي قمت بتحويلها إلى C#.لقد قمت بتضمينه أدناه دون سبب محدد (قد يحتوي هذا الرمز على بعض الأخطاء).

using System.Collections.Generic;
using System.Threading;

namespace ThreadSafeQueue {
    public class ThreadSafeQueue<T> {
        private Queue<T> _queue;

        public ThreadSafeQueue() {
            _queue = new Queue<T>();
        }

        public void EnqueueSafe(T item) {
            lock ( this ) {
                _queue.Enqueue(item);
                if ( _queue.Count >= 1 )
                    Monitor.Pulse(this);
            }
        }

        public T DequeueSafe() {
            lock ( this ) {
                while ( _queue.Count <= 0 )
                    Monitor.Wait(this);

                return this.DeEnqueueUnblock();

            }
        }

        private T DeEnqueueUnblock() {
            return _queue.Dequeue();
        }
    }
}

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

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

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