سؤال

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

من منظور الأداء، ما مدى أهمية تغيير الكود لاستخدام الأدوية العامة؟أعلم من منظور الأداء، أن الملاكمة وفتح الملاكمة وما إلى ذلك، غير فعالة، ولكن ما مقدار مكاسب الأداء التي ستحققها حقًا من تغييرها؟هل الأدوية العامة شيء يجب استخدامه على أساس المضي قدمًا، أم أن هناك تغييرًا كافيًا في الأداء بحيث ينبغي بذل جهد ضمير لتحديث الكود القديم؟

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

المحلول

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

أود أن أقترح:

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

بالطبع هناك أسباب أخرى غير الأداء للتغيير إلى الأدوية العامة:

  • أقل عرضة للخطأ، نظرًا لأن لديك فحصًا للأنواع في وقت الترجمة
  • أكثر قابلية للقراءة، فلن تحتاج إلى الإرسال في كل مكان ومن الواضح ما هو النوع المخزن في المجموعة
  • إذا كنت تستخدم الأدوية الجنيسة في المستقبل، فمن الأفضل استخدامها في كل مكان

نصائح أخرى

هذه هي النتائج التي حصلت عليها من تحليل بسيط لسلسلة من ملف بحجم 100 كيلو بايت 100000 مرة.استغرقت القائمة العامة (من الأحرف) 612.293 ثانية لتصفح الملف 100000 مرة.استغرقت ArrayList 2,880.415 ثانية لتصفح الملف 100,000 مرة.وهذا يعني في هذا السيناريو (كما عدد الأميال الخاصة بك سوف تختلف) القائمة العامة (من الحرف) أسرع بـ 4.7 مرة.

إليك الكود الذي قمت بتشغيله 100000 مرة:

Public Sub Run(ByVal strToProcess As String) Implements IPerfStub.Run
    Dim genList As New ArrayList

    For Each ch As Char In strToProcess.ToCharArray
        genList.Add(ch)
    Next

    Dim dummy As New System.Text.StringBuilder()
    For i As Integer = 0 To genList.Count - 1
        dummy.Append(genList(i))
    Next

End Sub

 Public Sub Run(ByVal strToProcess As String) Implements IPerfStub.Run
     Dim genList As New List(Of Char)

     For Each ch As Char In strToProcess.ToCharArray
         genList.Add(ch)
     Next

     Dim dummy As New System.Text.StringBuilder()
     For i As Integer = 0 To genList.Count - 1
         dummy.Append(genList(i))
     Next
 End Sub

الطريقة الوحيدة لمعرفة ذلك على وجه اليقين هي إنشاء ملف تعريف للتعليمات البرمجية الخاصة بك باستخدام أداة مثل dotTrace.

http://www.jetbrains.com/profiler/

من الممكن أن تكون عملية الملاكمة/إلغاء التغليف أمرًا تافهًا في تطبيقك الخاص ولا تستحق إعادة البناء.من الآن فصاعدًا، لا يزال يتعين عليك التفكير في استخدام الأدوية العامة نظرًا لسلامة نوع وقت الترجمة.

يجب استخدام الأدوية العامة، سواء Java أو .NET، للتصميم وسلامة الكتابة، وليس للأداء.يختلف Autoboxing عن الأدوية العامة (كائن ضمني بشكل أساسي للتحويلات البدائية)، وكما ذكرت، يجب ألا تستخدمها بدلاً من البدائية إذا كان هناك الكثير من العمليات الحسابية أو العمليات الأخرى التي ستتسبب في تحقيق أداء من التكرار إنشاء/تدمير الكائن الضمني.

بشكل عام، أود أن أقترح استخدام المضي قدمًا، وتحديث التعليمات البرمجية الموجودة فقط إذا كانت بحاجة إلى التنظيف لأغراض سلامة النوع/التصميم، وليس الأداء.

يعتمد ذلك على أن أفضل إجابة هي إنشاء ملف تعريف للكود الخاص بك والاطلاع عليه.أنا أحب AQTime ولكن يوجد عدد من الحزم لهذا الغرض.

بشكل عام، إذا تم استخدام قائمة ArrayList كثيرًا، فقد يكون من المفيد تحويلها إلى إصدار عام.ومع ذلك، فمن المرجح أنك لن تتمكن حتى من قياس الفرق في الأداء.تعد عملية الملاكمة وفك التغليف خطوات إضافية، لكن أجهزة الكمبيوتر الحديثة سريعة جدًا بحيث لا يحدث أي فرق تقريبًا.نظرًا لأن ArrayList هي في الواقع مجرد مصفوفة عادية ذات غلاف لطيف، فمن المحتمل أن ترى المزيد من الأداء المكتسب من اختيار أفضل لبنية البيانات (ArrayList.Remove هو O(n)!) مقارنة بالتحويل إلى الأدوية العامة.

يحرر:لدى Outlaw Programmer نقطة جيدة، ستظل تتنافس مع الأدوية الجنيسة وتفتحها، وهذا يحدث ضمنيًا.كل التعليمات البرمجية حول التحقق من الاستثناءات والأصفار من الصب والكلمات الرئيسية "is/as" ستساعد قليلاً.

أكبر المكاسب ستجدها في مراحل الصيانة.تعتبر الأدوية العامة أسهل بكثير في التعامل معها وتحديثها، دون الاضطرار إلى التعامل مع مشكلات التحويل والإرسال.إذا كان هذا هو الرمز الذي تزوره باستمرار، فبذل الجهد بكل الوسائل.إذا كان هذا رمزًا لم يتم التطرق إليه منذ سنوات، فلن أزعجك حقًا.

ما علاقة autoboxing/unboxing بالأدوية العامة؟هذه مجرد مشكلة تتعلق بسلامة النوع.مع المجموعة غير العامة، يُطلب منك الرجوع بشكل صريح إلى النوع الفعلي للكائن.مع الأدوية الجنيسة، يمكنك تخطي هذه الخطوة.لا أعتقد أن هناك فرق في الأداء بطريقة أو بأخرى.

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

ثم مرة أخرى، إذا كنت لا تعمل على شيء ما للعميل، فاستمر في قضاء بعض الوقت في إعادة البناء.سيؤدي ذلك إلى تحسين إمكانية قراءة الكود بنفسك.

يعتمد على مقدار ما هو موجود في التعليمات البرمجية الخاصة بك.إذا قمت بربط أو عرض قوائم كبيرة في واجهة المستخدم، فمن المحتمل أن ترى مكاسب كبيرة في الأداء.

إذا كانت قائمة ArrayList الخاصة بك متناثرة هنا وهناك، فمن المحتمل ألا يكون تنظيفها أمرًا كبيرًا، ولكنه لن يؤثر أيضًا على الأداء العام كثيرًا.

إذا كنت تستخدم الكثير من قوائم ArrayLists في التعليمات البرمجية الخاصة بك وسيكون من الصعب جدًا استبدالها (شيء قد يؤثر على جداولك)، فيمكنك اتباع نهج "إذا قمت بلمسها وتغييرها".

الشيء الرئيسي هو أن الأدوية العامة أسهل كثيرًا في القراءة، وأكثر استقرارًا عبر التطبيق نظرًا للكتابة القوية التي تحصل عليها منها.سوف ترى مكاسب ليس فقط من الأداء، ولكن أيضًا من قابلية صيانة التعليمات البرمجية واستقرارها.إذا كنت تستطيع أن تفعل ذلك بسرعة، أود أن أقول أن تفعل ذلك.

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

إذا كانت الكيانات الموجودة في ArrayLists هي أنواع كائنات، فستستفيد قليلاً من عدم تصنيفها في النوع الصحيح.إذا كانت أنواعًا ذات قيمة (بنيات أو عناصر أولية مثل Int32)، فإن عملية الملاكمة/إلغاء التغليف تضيف الكثير من الحمل، ويجب أن تكون المجموعات العامة أسرع بكثير.

إليك مقالة MSDN حول هذا الموضوع

تتمتع الأدوية العامة بأداء أفضل بكثير خاصة إذا كنت ستستخدم نوع القيمة (int، bool، struct وما إلى ذلك) حيث ستحصل على مكاسب ملحوظة في الأداء.

  1. يؤدي استخدام Arraylist مع أنواع القيمة إلى حدوث الملاكمة/إلغاء الملاكمة والتي إذا تم إجراؤها عدة مئات من المرات فستكون أبطأ بكثير من استخدام القائمة العامة.

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

كتبت عنه هنا.

يجب أن يعني استخدام الأدوية العامة أيضًا أن التعليمات البرمجية الخاصة بك ستكون أكثر بساطة وسهولة في الاستخدام إذا كنت تريد الاستفادة من أشياء مثل linq في إصدارات c# الأحدث.

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