سؤال

أحاول تنفيذ الكود التالي وأواصل الحصول على فهرس من استثناء النطاق عند محاولة تعيين قيم الصفيف إلى القائمة:-

        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 عنصرًا.

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