فهرس خارج نطاق استثناء عند استخدام التوازي للحلقة
-
25-09-2019 - |
سؤال
أحاول تنفيذ الكود التالي وأواصل الحصول على فهرس من استثناء النطاق عند محاولة تعيين قيم الصفيف إلى القائمة:-
int[] array = new int[1000000];
for (int i = 0; i < array.Length; i++)
{
array[i] = i;
}
List<int> list = new List<int>();
Parallel.For(0, array.Length, i => list.Add(array[i]));
أفعل شيئا خطأ هنا ؟ أنا أفهم أن العملية غير مرتبة/غير متزامنة ، ولكن لماذا تحصل "أنا" على قيم أعلى من قيمة "Array.Length"؟
المحلول
المشكلة هي أنه لا يمكنك الاتصال List.Add()
بالتزامن على خيوط متعددة. إذا كنت بحاجة إلى مجموعات آمنة من مؤشرات الترابط ، انظر System.Collections.Concurrent
مساحة الاسم.
إذا اقتحمت مصحح الأخطاء عندما تحصل على استثناء ، فسترى ذلك i
هو ليس أكثر من array.Length
, ، ولكن بدلاً من ذلك قوة 2 أقل بكثير من قوة array.Length
. ما يحدث هو أن List
يبدأ بمجموعة فارغة من شيء مثل 4 عناصر. كلما قمت بإضافة عنصر إلى قائمة ممتلئة صفيفها ، فإنها تنشئ مجموعة من ضعف طول الصفيف القديم ، وتنسخ العناصر القديمة إليها ، وتخزن الصفيف الجديد.
الآن دعنا نقول أن قائمتك تصل إلى 31 عنصرًا (وهذا يعني أن مساحة واحدة أخرى) وحاول خيطان إضافة عنصر 32. سيقوم كلاهما بتنفيذ رمز مثل هذا:
if (_size == _items.Length)
{
EnsureCapacity(_size + 1);
}
_items[_size++] = item;
أولاً سيرون ذلك _size
(31) ليس _items.Length
(32) ، لذلك ينفذ كلاهما _size++
. سيحصل الخيط الأول على 31 (الفهرس الصحيح للعنصر 32) ويتغير _size
إلى 32. سيحصل الخيط الثاني على 32 ويحاول الفهرس _items[32]
, ، مما يمنحك استثناءك لأنه يحاول الوصول إلى العنصر الثالث والثلاثين من مجموعة من 32 عنصرًا.