c# - حقل مقابل الممتلكات. تحسين الأداء




.net performance (4)

قد يكون التفسير الوحيد هو أن CLR يقوم بتحسين إضافي (يميزني إذا كنت مخطئا هنا).

نعم ، يطلق عليه المينا. يتم ذلك في المجمع (مستوى رمز الجهاز - أي JIT). بما أن الـ getter / setter تافهة (أي رمز بسيط جداً) يتم إتلاف مكالمات الطريقة ويكتب المكتوب / setter في الكود المحيط.

هذا لا يحدث في وضع التصحيح من أجل دعم التصحيح (أي القدرة على تعيين نقطة توقف في getter أو setter).

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

لا أعتقد أنه في التطبيق الفعلي حيث يتم استخدام هذه الخصائص بطريقة أكثر تطوراً ، سيتم تحسينها بنفس الطريقة.

العالم مليء بأوهام خاطئة. سيتم تحسينها لأنها لا تزال تافهة (مثل رمز بسيط ، لذلك فهي مدمجة).

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

الآن على السؤال. لطالما افترضت أنه لأن C # getters / setters هم حقا أساليب متخفية ، فإن قراءة المجال العام يجب أن تكون أسرع من الاتصال بـ getter.

لذلك تأكد من أنني أجريت اختبارًا (الرمز أدناه). لكن هذا الاختبار ينتج فقط النتائج المتوقعة (أي أن الحقول أسرع من الحصول على 34٪ ) إذا قمت بتشغيلها من داخل Visual Studio.

بمجرد تشغيله من سطر الأوامر فإنه يظهر إلى حد كبير نفس التوقيت ...

قد يكون التفسير الوحيد هو أن CLR يقوم بتحسين إضافي (صححني إذا كنت مخطئًا هنا).

لا أعتقد أنه في التطبيق الفعلي حيث يتم استخدام هذه الخصائص بطريقة أكثر تطوراً ، سيتم تحسينها بنفس الطريقة.

الرجاء مساعدتي لإثبات أو دحض فكرة أن العقارات في الواقع تكون أبطأ من الحقول.

السؤال هو - كيف يمكنني تعديل فئات الاختبار لإجراء تغيير السلوك CLR حتى الحقل العام outperfroms getters. أو أرني أن أي خاصية بدون منطق داخلي ستؤدي نفس حقل (على الأقل على برنامج التركات)

تحرير: أنا أتحدث فقط عن الإصدار x 64 الإصدار.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Runtime.InteropServices;

namespace PropertyVsField
{
    class Program
    {
        static int LEN = 20000000;
        static void Main(string[] args)
        {
            List<A> a = new List<A>(LEN);
            List<B> b = new List<B>(LEN);

            Random r = new Random(DateTime.Now.Millisecond);

            for (int i = 0; i < LEN; i++)
            {
                double p = r.NextDouble();
                a.Add(new A() { P = p });
                b.Add(new B() { P = p });
            }

            Stopwatch sw = new Stopwatch();

            double d = 0.0;

            sw.Restart();
            for (int i = 0; i < LEN; i++)
            {
                d += a[i].P;
            }

            sw.Stop();

            Console.WriteLine("auto getter. {0}. {1}.", sw.ElapsedTicks, d);

            sw.Restart();
            for (int i = 0; i < LEN; i++)
            {
                d += b[i].P;
            }

            sw.Stop();

            Console.WriteLine("      field. {0}. {1}.", sw.ElapsedTicks, d);

            Console.ReadLine();
        }
    }

    class A
    {
        public double P { get; set; }
    }
    class B
    {
        public double P;
    }
}

إلقاء نظرة على خصائص مقابل الحقول - لماذا لا يهم؟ (جوناثان Aneja) مقالة بلوق من أحد أعضاء فريق VB على MSDN. ويوضح الخاصية مقابل حجة الحقول ويشرح أيضًا الخصائص التافهة على النحو التالي:

إحدى الحجج التي سمعتها عن استخدام الحقول على الخصائص هي أن "الحقول أسرع" ، ولكن بالنسبة للخصائص التافهة غير الصحيحة في الواقع ، حيث سيضمن برنامج التحويل البرمجي في الوقت المناسب (JIT) CLR الوصول إلى الخاصية ويولد رمزًا كما هو كفاءة الوصول إلى حقل مباشرة.


ستضمن JIT أية طريقة (وليس مجرد getter) التي تحددها مقاييسها الداخلية بشكل أسرع. وبالنظر إلى أن الخاصية القياسية هي return _Property; سيكون مدمج في كل حالة.

السبب في رؤية سلوك مختلف هو أنه في وضع التصحيح مع مصحح المرفقات ، JIT معوق بشكل كبير ، لضمان مطابقة أي مواقع مكدس ما تتوقعه من التعليمات البرمجية.

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


كما ذكر آخرون بالفعل ، يميل الحصول على.

إذا كنت ترغب في تجنب التضمين ، يجب عليك

  • استبدال الخصائص التلقائية بالأخرى اليدوية:

    class A 
    {
        private double p;
        public double P
        {
            get { return p; }
            set { p = value; }
        }
    } 
    
  • وأخبر المترجم بعدم تضمين الـ getter (أو كلاهما ، إذا كنت ترغب في ذلك):

            [MethodImpl(MethodImplOptions.NoInlining)]
            get { return p; }
    

لاحظ أن التغيير الأول لا يُحدث اختلافًا في الأداء ، في حين أن التغيير الثاني يُظهر ارتفاعًا في تكلفة استدعاء الأسلوب:

الخصائص اليدوية:

auto getter. 519005. 10000971,0237547.
      field. 514235. 20001942,0475098.

لا يوجد تداخل للإنبات:

auto getter. 785997. 10000476,0385552.
      field. 531552. 20000952,077111.






optimization