كيف يمكنني إنتاج سلاسل الرسائل على مراكز مختلفة لوحدة المعالجة المركزية؟

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

سؤال

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

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

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

المحلول

لا تهتم بفعل ذلك.

بدلا من ذلك استخدم تجمع موضوع.تجمع مؤشرات الترابط عبارة عن آلية (في الواقع فئة) لإطار العمل يمكنك الاستعلام عن مؤشر ترابط جديد.

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

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

نصائح أخرى

ليس من الضروري أن يكون الأمر بسيطًا مثل استخدام تجمع مؤشرات الترابط.

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

بالنسبة لمعظم التطبيقات، وبالتأكيد بالنسبة لتشفير WAV وMP3، يجب عليك تحديد عدد مؤشرات الترابط العاملة على عدد وحدات المعالجة المركزية المتاحة.فيما يلي بعض رموز C# للعثور على عدد وحدات المعالجة المركزية:

int processors = 1;
string processorsStr = System.Environment.GetEnvironmentVariable("NUMBER_OF_PROCESSORS");
if (processorsStr != null)
    processors = int.Parse(processorsStr);

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

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

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

يمكنك أيضًا استكشاف System.Diagnostics.Process فصل.هناك يمكنك العثور على وظيفة لتعداد سلاسل العمليات كمجموعة من موضوع العملية أشياء.تحتوي هذه الفئة على طرق لتعيين ProcessorAffinity أو حتى تعيين ملف يفضل المعالج - لست متأكدا ما هو.

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

على الرغم من أنني أتفق مع معظم الإجابات هنا، إلا أنني أعتقد أنه من المفيد إضافة اعتبار جديد:تقنية سبيد ستيب.

عند تشغيل وحدة معالجة مركزية مكثفة ومهمة أحادية الترابط على نظام متعدد النواة، في حالتي Xeon E5-2430 مع 6 نوى حقيقية (12 مع HT) ضمن Windows Server 2012، انتشرت المهمة بين جميع النوى الـ 12، باستخدام حوالي 8.33% من كل نواة ولا تؤدي إلى زيادة السرعة أبدًا.ظلت وحدة المعالجة المركزية عند 1.2 جيجا هرتز.

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

هذا هو البرنامج الذي استخدمته، والذي يقوم فقط بتكرار زيادة المتغير.عند الاتصال بـ -a، سيتم تعيين التقارب إلى النواة 1.واستند الجزء التقارب على هذا المشنور.

using System;
using System.Diagnostics;
using System.Linq;
using System.Runtime.InteropServices;
using System.Threading;

namespace Esquenta
{
    class Program
    {
        private static int numThreads = 1;
        static bool affinity = false;
        static void Main(string[] args)
        {
            if (args.Contains("-a"))
            {
                affinity = true;
            }
            if (args.Length < 1 || !int.TryParse(args[0], out numThreads))
            {
                numThreads = 1;
            }
            Console.WriteLine("numThreads:" + numThreads);
            for (int j = 0; j < numThreads; j++)
            {
                var param = new ParameterizedThreadStart(EsquentaP);
                var thread = new Thread(param);
                thread.Start(j);
            }

        }

        static void EsquentaP(object numero_obj)
        {
            int i = 0;
            DateTime ultimo = DateTime.Now;
            if(affinity)
            {
                Thread.BeginThreadAffinity();
                CurrentThread.ProcessorAffinity = new IntPtr(1);
            }
            try
            {
                while (true)
                {
                    i++;
                    if (i == int.MaxValue)
                    {
                        i = 0;
                        var lps = int.MaxValue / (DateTime.Now - ultimo).TotalSeconds / 1000000;
                        Console.WriteLine("Thread " + numero_obj + " " + lps.ToString("0.000") + " M loops/s");
                        ultimo = DateTime.Now;
                    }
                }
            }
            finally
            {
                Thread.EndThreadAffinity();
            }
        }

        [DllImport("kernel32.dll")]
        public static extern int GetCurrentThreadId();

        [DllImport("kernel32.dll")]
        public static extern int GetCurrentProcessorNumber();
        private static ProcessThread CurrentThread
        {
            get
            {
                int id = GetCurrentThreadId();
                return Process.GetCurrentProcess().Threads.Cast<ProcessThread>().Single(x => x.Id == id);
            }
        }
    }
}

والنتائج:

results

سرعة المعالج، كما هو موضح من خلال مدير المهام، تشبه ما تشير إليه تقارير CPU-Z:

enter image description here

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

يمكنك بالتأكيد القيام بذلك عن طريق كتابة الروتين داخل برنامجك.

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

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

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

#define MAX_CORE 256
processor_mask[MAX_CORE] = {0};
core_number = 0;

Call GetLogicalProcessorInformation();
// From Here we calculate the core_number and also we populate the process_mask[] array
// which would be used later on to set to run different threads on different CORES.


for(j = 0; j < THREAD_POOL_SIZE; j++)
Call SetThreadAffinityMask(hThread[j],processor_mask[j]);
//hThread is the array of handles of thread.
//Now if your number of threads are higher than the actual number of cores,
// you can use reset the counters(j) once you reach to the "core_number".

بعد استدعاء الروتين أعلاه، سيتم تنفيذ سلاسل الرسائل دائمًا بالطريقة التالية:

Thread1-> Core1
Thread2-> Core2
Thread3-> Core3
Thread4-> Core4
Thread5-> Core5
Thread6-> Core6
Thread7-> Core7
Thread8-> Core8

Thread9-> Core1
Thread10-> Core2
...............

لمزيد من المعلومات، يرجى الرجوع إلى دليل/MSDN لمعرفة المزيد عن هذه المفاهيم.

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

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

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

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

إذا كان لديك موضوع للقراءة للتشغيل، وكان هناك نواة خاملة، فإن النواة سوف تشغيل الموضوع الخاص بك، لا تقلق.

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