كيف ترتبط الإطار التفاعلي ، PLINQ ، TPL والإضافات المتوازية ببعضها البعض؟

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

سؤال

على الأقل منذ إصدار .NET 4.0 ، يبدو أن Microsoft بذلت الكثير من الجهد لدعم البرمجة المتوازية وغير المتزامنة ويبدو أن الكثير من واجهات برمجة التطبيقات والمكتبات حول هذا الأمر قد ظهرت. لا سيما الأسماء الفاخرة التالية يتم ذكرها باستمرار في كل مكان في الآونة الأخيرة:

  • الإطار التفاعلي ،
  • plinq (LINQ الموازي) ،
  • TPL (المكتبة الموازية للمهمة) و
  • ملحقات موازية.

الآن يبدو أنهم جميعًا منتجات Microsoft ويبدو أنهم جميعًا يستهدفون سيناريوهات البرمجة غير المتزامنة أو المتوازية لـ .NET. لكن ليس من الواضح تمامًا ماهية كل منهم بالفعل وكيف يرتبط ببعضها البعض. قد يكون البعض في الواقع نفس الشيء.

بعبارة قليلة ، هل يمكن لأي شخص تعيين السجل مباشرة على ما هو؟

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

المحلول

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

على سبيل المثال ، دعنا نقول أن لديك مجموعة من الأوتار وتريد الحصول على كل تلك التي تبدأ بالحرف "A". يمكنك كتابة استفسارك مثل هذا:

var words = new[] { "Apple", "Banana", "Coconut", "Anvil" };
var myWords = words.Select(s => s.StartsWith("A"));

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

var myWords = words.AsParallel().Select(s => s.StartsWith("A"));

هذا كل ما عليك فعله لتحويل استعلام منتظم إلى مستشار موازٍ يعمل على نوى متعددة. أنيق جدا.


ال TPL (المكتبة الموازية للمهمة) هي نوع من المكملات لـ Plinq ، ويشكلون معًا امتدادات متوازية. في حين أن plinq يعتمد إلى حد كبير على أ وظيفي نمط البرمجة مع لا الآثار الجانبية ، الآثار الجانبية هي بالضبط ما هو TPL ل. إذا كنت تريد في الواقع اعمل بالتوازي بدلاً من مجرد البحث/اختيار الأشياء بالتوازي ، يمكنك استخدام TPL.

TPL هو أساسا Parallel الفصل الذي يكشف الحمولة الزائدة من For, Foreach, ، و Invoke. Invoke يشبه إلى حد ما في طابور المهام في ThreadPool, ، ولكن أبسط بعض الشيء للاستخدام. IMO ، البتات الأكثر إثارة للاهتمام هي For و Foreach. لذلك على سبيل المثال ، لنفترض أن لديك مجموعة كاملة من الملفات التي تريد ضغطها. يمكنك كتابة الإصدار المتسلسل العادي:

string[] fileNames = (...);
foreach (string fileName in fileNames)
{
    byte[] data = File.ReadAllBytes(fileName);
    byte[] compressedData = Compress(data);
    string outputFileName = Path.ChangeExtension(fileName, ".zip");
    File.WriteAllBytes(outputFileName, compressedData);
}

مرة أخرى ، كل تكرار لهذا الضغط مستقل تمامًا عن أي تكرار آخر. يمكننا تسريع هذا الأمر عن طريق القيام بالعديد منهم في وقت واحد:

Parallel.ForEach(fileNames, fileName =>
{
    byte[] data = File.ReadAllBytes(fileName);
    byte[] compressedData = Compress(data);
    string outputFileName = Path.ChangeExtension(fileName, ".zip");
    File.WriteAllBytes(outputFileName, compressedData);
});

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

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


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

أحد أروع الأمثلة التي وجدتها من RX هي هنا. انتقل إلى قسم "linq to iobservable" حيث يقوم بتنفيذ معالج السحب والإفلات ، وهو عادة ما يكون ألمًا في WPF ، في 4 أسطر فقط من التعليمات البرمجية. RX يعطيك تعبير من الأحداث ، شيء لا تملكه حقًا مع معالجات الأحداث العادية ، ومقتطفات التعليمات البرمجية مثل هذه هي أيضًا واضحة لإعادة تشكيل فئات السلوك التي يمكنك كم في أي مكان.


وهذا كل شيء. هذه هي بعض الميزات الباردة المتوفرة في .NET 4.0. هناك العديد من الأشياء ، بالطبع ، لكن هؤلاء كانوا هم الذين سألتهم!

نصائح أخرى

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

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

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

سيكون RX ما يجب على معظم المطورين استخدامه. هذه هي الطريقة التي يمكن أن "تتفاعلها" تطبيقات WPF بالرسائل الخارجية مثل البيانات الخارجية (دفق رسائل IM إلى عميل IM) أو إدخال خارجي (مثل مثال سحب الماوس المرتبط من Aaronaught). تحت الأغطية ، تستخدم RX Primitives من TPL/BCL ، ومجموعات ThreadSafe من TPL/BCL ، وكائنات وقت التشغيل مثل ThreadPool. في رأيي RX هو "أعلى مستوى" للبرمجة للتعبير عن نواياك.

ما إذا كان المطور العادي يمكن أن يلفت رأسه حول مجموعة النوايا التي يمكنك التعبير عنها مع RX لم يتم رؤيتها بعد. قون

لكنني أعتقد أن العامين المقبلين TPL مقابل RX سيكون النقاش التالي مثل إطار عمل LINQ-to-SQL مقابل الكيان. هناك نوعان من النكهات من API في نفس المجال وتتخصص في سيناريوهات مختلفة ولكن تتداخل بعدة طرق. ولكن في حالة TPL & RX ، فإنهم يدركون فعليًا بعضهم البعض ، وهناك محولات مدمجة لتكوين التطبيقات واستخدام كلا الإطارين معًا (مثل نتائج التغذية من حلقة PLINQ في دفق RX قابل للرسوم). بالنسبة للأشخاص الذين لم يفعلوا أي برمجة موازية ، هناك الكثير من التعلم للوصول إلى السرعة.

تحديث: لقد كنت أستخدم كل من TPL و RXNET في عملي العادي على مدار الـ 6 أشهر الماضية (خلال 18 شهرًا منذ إجابتي الأصلية). أفكاري المفضلة من TPL و/أو Rxnet في خدمة WCF من الدرجة المتوسطة (خدمة LOB Enterprise): http://yzorgsoft.blogspot.com/2011/09/middle-tier-tpl-nor-rxnet.html

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