Multithreading: كيفية معالجة البيانات في ناقل ، بينما يتم ملء المتجه؟

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

سؤال

لديّ تطبيق Linux ذو الخيال الواحد الذي أود أن أجعله بالتوازي. يقرأ ملف بيانات ، ويقوم بإنشاء كائنات ، ويضعها في متجه. ثم يستدعي طريقة كثيفة الحساب (.5 ثانية+) على كل كائن. أريد أن أتصل بالطريقة بالتوازي مع إنشاء الكائن. بينما نظرت إلى QT و TBB ، أنا منفتح على خيارات أخرى.

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

QtConcurrent::map(Iter begin,Iter end,function()) تبدو سهلة للغاية ، لكن لا يمكنني استخدامه على متجه يتغير في الحجم ، هل يمكنني ذلك؟ وكيف أخبرها أن تنتظر المزيد من البيانات؟

نظرت أيضًا إلى TBB من Intel ، لكن يبدو أن موضوعي الرئيسي سيتوقف إذا استخدمت parallel_for أو parallel_while. هذا ينتن ، منذ أن أوصى مدير الذاكرة الخاص بهم (Open MMGT's MMGT لديه أداء ضعيف عند تعدد التربعات من العمر).

/**intended to be called by a thread
\param start the first item to get from the vector
\param skip how many to skip over (4 for 4 threads)
*/
void g2m::makeSolids(uint start, uint incr) {
  uint curr = start;
  while ((!interpDone) || (lineVector.size() > curr)) {
    if (lineVector.size() > curr) {
      if (lineVector[curr]->isMotion()) {
        ((canonMotion*)lineVector[curr])->setSolidMode(SWEPT);
        ((canonMotion*)lineVector[curr])->computeSolid();
      }
      lineVector[curr]->setDispMode(BEST);
      lineVector[curr]->display();

      curr += incr;
    } else {
      uio::sleep(); //wait a little bit for interp
    }
  }
}

تحرير: لتلخيص ، ما هي أبسط طريقة لمعالجة المتجه في نفس الوقت الذي يقوم فيه الخيط الرئيسي بملء المتجه؟

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

المحلول

من الصعب معرفة ما إذا كنت تفكر في هذه المشكلة بعمق وهناك أكثر مما تتركه ، أو إذا كنت أكثر من التفكير في ذلك ، أو إذا كنت حذرًا من الخيط.

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

لماذا هذا أكثر تعقيدًا من شيء من هذا القبيل (في الكود الكاذب الخام):

while (! eof)
{
    readfile;
    object O(data);
    push_back(O);
    pthread_create(...., O, makeSolid);
}


while(x < vector.size())
{
    pthread_join();
    x++;
}

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

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

نصائح أخرى

أولاً ، للاستفادة من الخيوط ، تحتاج إلى العثور على مهام بطيئة بالمثل لكل موضوع للقيام به. قلت أن المعالجة لكل كائن تستغرق .5S+، ما هي المدة التي تستغرقها قراءة الملف / إنشاء الكائن؟ يمكن أن يكون بسهولة عُشر أو ألف من ذلك الوقت ، وفي هذه الحالة ، سيؤدي نهجك المتعدد القراءة إلى تحقيق فائدة سلبية. إذا كان هذا هو الحال ، (نعم ، سأجيب على سؤالك الأصلي قريبًا في حالة عدم وجوده) ، ففكر في معالجة كائنات متعددة في وقت واحد. نظرًا للمعالجات الخاصة بك تستغرق بعض الوقت ، فإن إنشاء مؤشرات الترابط النفقات العامة ليست ذات أهمية فظيعة ، لذلك يمكنك ببساطة أن تولد مؤشر ترابط قراءة الملف الرئيسي/إنشاء الكائن مؤشر ترابط جديد وتوجيهه إلى الكائن الذي تم إنشاؤه حديثًا. ثم يواصل الخيط الرئيسي قراءة/إنشاء كائنات لاحقة. بمجرد قراءة/إنشاء جميع الكائنات ، وجميع مؤشرات ترابط المعالجة التي تم إطلاقها ، فإن الخيط الرئيسي "ينضم" (ينتظر) مؤشرات ترابط العمال. إذا كان هذا سيؤدي إلى إنشاء العديد من المواضيع (الآلاف) ، فضع حدًا على مدى مسموح لخيط الخيط الرئيسي بالوصول إلى: قد يقرأ/إنشاء 10 كائنات ثم انضم إلى 5 ، ثم قراءة/إنشاء 10 ، انضم إلى 10 ، قراءة/إنشاء 10 ، انضم 10 إلخ حتى الانتهاء.

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

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

Caleb: تمامًا - ربما كان ينبغي علي التأكيد نشيط الخيوط. يجب دائمًا اعتبار موضوع واجهة المستخدم الرسومية واحدًا.

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