Pitfalls المحتملة في بيانات و مهمة Parallelism
في كثير من الحالات، ParallelFor()و ParallelForEach()يمكن أن توفر تحسينات الأداء الهامة عبر العادية حلقات متسلسلة. ومع ذلك، العمل من parallelizing تكرار حلقي يقدم التعقيد الذي قد يؤدي إلى مشاكل، في تعليمات برمجية متسلسلة، ليست شائعة أو لم يتم العثور في كل. يسرد هذا الموضوع بعض الممارسات لتجنب عند كتابة متوازى حلقات.
غير افتراض التي متوازى دوماً هو أسرع
في بعض الحالات متوازى تكرار حلقي قد يعمل بسرعة أقل من يعادلها متسلسلة. قاعدة أساسى أساسى هو أن تكون الحلقات المتوازية التي تحتوي على عدة مرات التكرار والتفويضات السريع المحتمل زيادةالسرعة كثيرا. على الرغم من ذلك، نظراً لأن العديد من العوامل المتعلقة بالأداء، نوصي دائماً المقياس نتائج الفعلية.
تجنب الكتابة إلى مواقع? ذاكرة المشتركة
في تعليمات برمجية متسلسلة، فإنه هو غير معروفة للقراءة من أو الكتابة إلى المتغيرات الثابتة أو حقول الفئة. ومع ذلك، كلما مؤشرات ترابط متعددة تحاول الوصول إليها هذه المتغيرات بشكل متزامن، هو احتمال كبير لحالات السباق. على الرغم من أن يمكن استخدم يمكن للتأمين لمزامنة الوصول إلى المتغير، تكلفة المزامنة hurt الأداء. ولذلك، نوصي أن يمكنك تجنب، أو الأقل الحد، الوصول إلى مشاركة الولاية في متوازى تكرار حلقي قدر الإمكان. أفضل طريقة للقيام بترتيب هو هو لاستخدام التحميلات الزائدة من ParallelFor()و ParallelForEach()التي تستخدم System.Threading.ThreadLocal<T>متغير لتخزين الولاية مؤشر ترابط المحلية أثناء تنفيذ تكرار حلقي. للمزيد من المعلومات، راجع كيفية القيام بما يلي: تكرار حلقي متوازى.For والتي يحتوي على جزء الترابط-محلي متغيرات الكتابة وكيفية القيام بما يلي: تكرار حلقي متوازى.ForEach والتي انتهت الكتابة مؤشر ترابط-المتغيرات المحلية.
تجنب Over-Parallelization
باستخدام متوازى حلقات، التي تتطلب جهاز عرض تكاليف تقسيم مجموعة المصدر وتزامن مؤشرات ترابط العاملين. يتم زيادة محدودا فوائد parallelization رقم من المعالجات في الكمبيوتر. هناك هو لا زيادةالسرعة أن يتم gained بتشغيل عمليات جزئية المرتبطة بجهازك متعددة تشغيل معالج واحد فقط. ولذلك، يجب أن تكون حذراً غير إلى over-parallelize تكرار حلقي.
يمكن أن يحدث السيناريو الأكثر شيوعاً في أي over-parallelization هو في حلقات متداخلة. في معظم الحالات، فإنه هو أفضل parallelize الحلقة الخارجية فقط إلا إذا كان يطبق واحد أو المزيد الشروط التالية:
تكرار حلقي داخلية هو تعرف أن طويل جداً.
كنت تقوم حساب تكلفة تشغيل كل طلب. (يظهر في المثال تشغيل هو غير مكلفة.)
نظام الهدف هو تعرف أن معالجات كافية لمعالجة عدد عمليات جزئية التي سيتم إنتاجها بواسطة الاستعلام تشغيل parallelizing cust.Orders.
في الجميع الحالات، أن أفضل طريقة لتحديد شكل الأمثل الاستعلام هو لاختبار وقياس.
تجنب المكالمات إلى غير-مؤشر ترابط آمن وظائف
الكتابة إلى وظائف مثيل غير مؤشر ترابط-اﻷمن من متوازى تكرار حلقي يؤدي إلى تلف بيانات التي قد أو قد لا انتقال التي لم يتم كشفها في البرنامج الخاص بك. قد يؤدي أيضا إلى استثناءات. في المثال التالي، مؤشرات ترابط متعددة قد تكون محاولة استدعاء FileStreamWrite()الأسلوب في نفس الوقت، مما هو غير معتمد من قبل فئة.
[Visual Basic]
Dim fs As FileStream = File.OpenWrite(…)
Dim nums() as Int = …
Parallel.ForEach(nums, Sub(n) fs.Write(n))
[C#]
FileStream fs = File.OpenWrite(…);
int[] nums = …
Parallel.ForEach(nums, Sub(n) fs.Write(n))
حد يستدعي إلى مؤشر ترابط-الأمن وظائف
الطرق الأكثر ثابتة في.NET Framework مؤشر ترابط-آمن و يمكن استدعاؤها من مؤشرات ترابط متعددة شكل متزامن. على الرغم من ذلك، حتى في هذه الحالات، قد يؤدي المزامنة المتضمنة إلى slowdown هامة في الاستعلام.
ملاحظة |
---|
يمكنك اختبار هذا نفسك بواسطة إدراج بعض الاستدعاءات إلى WriteLineفي الاستعلامات.وعلى الرغم من أنه يتم استخدام هذه الطريقة في الأمثلة الوثائق لأغراض العرض التوضيحي، لا تستخدمه في حلقات متوازية إلا إذا necessary.h |
تكون على علم بالمشاكل المتعلقة بالترابط لمؤشر الترابط
بعض التقنيات، تشغيل سبيل المثال، COM التوافق للمكونات للأجزاء مفرد-Threaded (STA) Windows Forms "البنية الأساسية لبرامج" العروض التقديمية Windows (WPF)، تفرض قيود تقارب مؤشر الترابط التي تتطلب التعليمة البرمجية لتشغيل تشغيل مؤشر ترابط معينة. ل مثال، في كل من Windows Forms و WPF، عنصر تحكم يمكن الوصول إلى فقط تشغيل مؤشر ترابط الذي تم إنشاؤها عليه. وهذا يعني، تشغيل سبيل المثال، أنه لا يمكنك تحديث عنصر تحكم القائمة من متوازى تكرار حلقي إلا إذا قمت بتكوين جدولة مؤشر ترابط جدولة العمل تشغيل مؤشر الترابط واجهة المستخدم فقط. لمزيد من المعلومات، راجع كيفية القيام بما يلي: جدولة العمل في سياق معين المزامنة.
استخدم تنبيه عند جارى الإنتظار في مفوضون التي هل به بواسطة متوازى.Invoke
في بعض الحالات، سوف متوازى مكتبة المهام المضمنة مهمة، مما يعني أنه يعمل تشغيل المهمة تشغيل مؤشر ترابط قيد التنفيذ حاليا. لمزيد من المعلومات، راجع Schedulers مهمة. يمكن أن يؤدي هذا أمثلية الأداء إلى حالة توقف تام في حالات معينة. على سبيل المثال، قد على مهمتين يعمل المفوض نفس تعليمات برمجية إشارات عند حدوث حدث ما، ثم انقر فوق انتظار غير ذلك للإشارة للمهمة. إذا كانت مهمة ثانية هو inlined تشغيل نفس مؤشر ترابط كما أول، ووصول أول في الولاية انتظار، سيتم مهمة ثانية لن تكون قادراً تشغيل إشارة حدث الخاص به. لتجنب مثل هذا تكرار، يمكنك تحديد المهلة المحددة في عملية الانتظار أو لا يمكن حظر استخدام المنشئات مؤشر ترابط واضح للمساعدة في ضمان أن مهمة واحدة غير ذلك.
قم بافتراض عدم Iterations (تكرارات) هذه من ForEach، عن و ForAll دائماً بالتنفيذ في متوازى
هو المهم ضع في اعتبارك أن التكرار الفردية في For()، ForEach()أو ForAll()قد يتكرر ولكن لم يتم تنفيذه في نفس الوقت. ولذلك، يجب تجنب كتابة أي تعليمات برمجية يعتمد هذا للتصحيح تشغيل التنفيذ المتوازي للتكرار أو تنفيذ عمليات التكرار في أي ترتيب معين.
على سبيل المثال، رقم هو رمز هو المحتمل أن حالة توقف تام:
[Visual Basic]
Dim mre = New ManualResetEventSlim()
Enumerable.Range(0, ProcessorCount * 100).AsParallel().ForAll(Sub(j)
If j = Environment.ProcessorCount Then
Console.WriteLine("Set on {0} with value of {1}", Thread.CurrentThread.ManagedThreadId, j)
mre.Set()
Else
Console.WriteLine("Waiting on {0} with value of {1}", Thread.CurrentThread.ManagedThreadId, j)
mre.Wait()
End If
End Sub) ' deadlocks
[C#]
ManualResetEventSlim mre = new ManualResetEventSlim();
Enumerable.Range(0, ProcessorCount * 100).AsParallel().ForAll((j) =>
{
if (j == Environment.ProcessorCount)
{
Console.WriteLine("Set on {0} with value of {1}", Thread.CurrentThread.ManagedThreadId, j);
mre.Set();
}
else
{
Console.WriteLine("Waiting on {0} with value of {1}", Thread.CurrentThread.ManagedThreadId, j);
mre.Wait();
}
}); //deadlocks
في هذا المثال، تعيين تكرار واحد حدث ما، و الانتظار الجميع التكرارات الأخرى تشغيل الحدث. لا توجد أية جارى الإنتظار مكتمل عملية التكرار حتى يتم اكتمال تكرار حدث-إعداد. ومع ذلك، فإنه هو المحتملة مرات التكرار للانتظار بحظر الجميع عمليات جزئية التي يتم استخدامها لتنفيذ تكرار حلقي المتوازية، قبل أن تنته تكرار حدث-إعداد فرصة لتنفيذ. ينتج عن هذا في حالة توقف تام – حدث-تعيين تكرار سيقوم بعدم ينفذ، وسوف لن تنبيه مرات تكرار للانتظار.
في محدد، وتكرار واحد من متوازى تكرار حلقي سينتظره مطلقا تشغيل تكرار آخر من تكرار حلقي لجعل التقدم. إذا كان متوازى يقرر تكرار حلقي لجدولة التكرارات شكل متسلسل، ولكن بترتيب عكسي، يحدث حالة توقف تام.
تجنب تنفيذ متوازى الكهربية في مؤشر ترابط وجهه المستخدم
هو هامة الحفاظ على استجابة واجهة مستخدم (واجه مستخدم) للتطبيق الخاص بك. إذا تضمن عملية عمل كافية إلى تضمن parallelization، ثم أنه من المحتمل أن يكون يجب عدم تشغيل تلك العملية على مؤشر الترابط واجهة المستخدم. بدلاً من ذلك، يجب تجاهلها هذه العملية إلى تشغيل تشغيل مؤشر ترابط الخلفية. على سبيل المثال، إذا كنت تريد استخدام متوازى تكرار حلقي لحساب بعض بيانات التي يجب تقديمها فيما بعد في عنصر تحكم واجهة مستخدم، يجب مراعاة تنفيذ تكرار حلقي بداخل مثيل مهمة بدلاً من مباشرة في معالج أحداث واجهة مستخدم. فقط عند اكتمال احتساب الأساسية يجب أن تقوم ثم تنظيم واجه المستخدم التحديث مرة أخرى إلى واجه المستخدم مؤشر الترابط.
في حالة القيام بتشغيل متوازي تكرار حلقي s تشغيل مؤشر الترابط واجهة المستخدم، احرص تشغيل تجنب جاري الآن التحديث عناصر واجهة المستخدم من داخل تكرار حلقي. محاولة تحديث عناصر واجهة المستخدم من خلال جنبا إلى جنب تكرار حلقي هو تنفيذ تشغيل مؤشر الترابط واجهة المستخدم قد يؤدي إلى تلف الولاية الاستثناءات، التحديثات المتأخر و deadlocks الزوجية، استناداً إلى كيفية استدعاء التحديث واجهة المستخدم. في المثال التالي، التوازي تكرار حلقي يمنع مؤشر ترابط واجهة المستخدم بحيث أنه يقوم بتنفيذ حتى يتم إكمال الجميع التكرارات. ومع ذلك، إذا تكرار الحلقة هو قيد التشغيل تشغيل مؤشر ترابط الخلفية (ك For()قد نفذ)، يؤدي استدعاء Invoke رسالة لإرسالها إلى مؤشر ترابط واجهة المستخدم ومنع هذه الرسالة للمعالجة في انتظار. منذ مؤشر ترابط واجهة المستخدم هو حظر تشغيل For()، لا يمكن معالجة الرسالة، ومؤشر ترابط واجه المستخدم deadlocks.
[Visual Basic]
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim iterations As Integer = 20
Parallel.For(0, iterations, Sub(x)
Button1.Invoke(Sub()
DisplayProgress(x)
End Sub)
End Sub)
End Sub
[C#]
private void button1_Click(object sender, EventArgs e)
{
Parallel.For(0, N, i =>
{
// do work for i
button1.Invoke((Action)delegate { DisplayProgress(i); });
});
}
يوضح المثال التالي كيفية إلى تجنب توقف تام، ومن خلال تنفيذ تكرار حلقي بداخل مثيل مهمة. واجهة مستخدم مؤشر ترابط هو حظره الحلقة لا، ويمكن معالجة الرسالة.
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim iterations As Integer = 20
Task.Factory.StartNew(Sub() Parallel.For(0, iterations, Sub(x)
Button1.Invoke(Sub()
DisplayProgress(x)
End Sub)
End Sub))
End Sub
private void button1_Click(object sender, EventArgs e)
{
Task.Factory.StartNew(() =>
Parallel.For(0, N, i =>
{
// do work for i
button1.Invoke((Action)delegate { DisplayProgress(i); });
})
);
}
راجع أيضًا:
المبادئ
البرمجة المتوازية في .NET Framework