ركوب الدراجات من خلال قائمة فرز - لماذا هذا أسرع؟

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

سؤال

List1 في المثال التالي هو قائمة فرز (myclass) وتحتوي على 251 عضوا.

أول اثنين من الكردز ينفذ في 15.5 ثانية.

 For cnt As Integer = 1 To 1000000
        For Each TempDE In List1
            Dim F As String = TempDE.Key
            TempDE.Value.x1 = 444
        Next
    Next

 

    For cnt As Integer = 1 To 1000000
        For Each TempDE As KeyValuePair(Of String, phatob) In List2
            Dim F As String = TempDE.Key
            TempDE.Value.x1 = 444
        Next
    Next

هذا واحد ينفذ في 5.6 ثانية.

    For cnt As Integer = 0 To 999999
        For cnt2 As Integer = 0 To 250
            Dim F As String = List1.Keys(cnt2)
            List1.Values(cnt2).x1 = 444
        Next

    Next

لماذا أول اثنين من الكاديفات أبطأ بكثير؟

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

المحلول

تقدم القائمة الفرز مجموعة من خلال تطبيق Icomparer لتوفير وظيفة الفرز. داخليا، فإنه ينفذ 2 صفائف لتخزين عناصر القائمة - صفيف واحد للمفتاح والأخرى للقيم. تم تحسين مجموعة .NET للوصول السريع والوصول العشوائي السريع.

شكوكي لماذا أول 2 بطيئة هي أن العبارة foreach في قائمة فرز هي عبارة عن مجمع حول العداد. سيتم استدعاء Calling Foreach للاستعلام عن العداد، استدعاء MoveNext والحديث. بالإضافة إلى ذلك، على الرغم من أن القائمة العامة يمكن أن تنطوي على الملاكمة وإلغاء تثبيتها أثناء تعبير القائمة، ويمكن أن تخلق الأداة المساعدة التي لن تحصل عليها عادة عن طريق الوصول إليها بواسطة الفهرس.

نصائح أخرى

حاولت أن أنظر حولها لبعض الوثائق حول كيف For Each يتصرف، لكنني لم أستطع العثور عليه.

نظريتي هي أن استخدام For Each تقوم البيانات بنسخ الكائن في القائمة إلى موضع آخر في الذاكرة ثم نسخها مرة أخرى في القائمة عند انتهاء كل تكرار للحلقة.

هناك احتمال آخر هو أنه يستدعي المنشئ في بداية كل التكرار ثم ينفصل ويمصل المنشئ مرة أخرى إعادة تعيينه للتكرار التالي.

لست متأكدا من أي من هذه النظريات، ولكن الفرق الرئيسي بين 3 و (1 أو 2) هو عدم وجود For Each.

تحرير: وجدت بعض الوثائق في MSDN..

إليك مقتطف:

عند إعدام لكل منهما ... يبدأ الحلقة التالية، يتحقق Visual Basic من أن المجموعة تشير إلى كائن مجموعة صالحة. إذا لم يكن كذلك، فإنه يلقي استثناء. خلاف ذلك، فإنه يستدعي طريقة movenext والخاصية الحالية لكائن العداد لإرجاع العنصر الأول. إذا كان moveneXT يشير إلى أنه لا يوجد عنصر مقبل، فهذا هو، إذا كانت المجموعة فارغة، فسيتم إنهاء كل حلقة وتحكم في العبارة بعد العبارة التالية. خلاف ذلك، يعطل Visual Basic Ender إلى العنصر الأول ويعمل كتلة العبارة.

بشكل عام يبدو وكأنه For Each هو أكثر "تدار" ويفعل الكثير من النفقات العامة للتأكد من أن كل شيء يطابق. نتيجة لذلك، الأمر أبطأ.

أعتقد أن برنامج التحويل البرمجي يمكنه تحسين كتلة 3 أفضل بسبب نطاق الحلقة الثابتة. في كتل واحد و 2، لن يعرف المحول البرمجي ما هو الحد الأعلى للحلقة حتى يقيم القائمة وبالتالي جعلها أبطأ.

تخمين عشوائي: List1 يحتوي على ~ 750 عناصر (وليس فقط 250). حالتك الثالثة أسرع، لأنه لا يتسبب في كل عنصر يسرد.

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