في Java هل هناك فرق أداء بين الإشارة إلى حقل من خلال Getter مقابل متغير؟

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

سؤال

هل هناك أي اختلافات بين القيام به

Field field = something.getSomethingElse().getField();
if (field == 0) {
//do something    
}
somelist.add(field);

مقابل

if (something.getSomethingElse().getField() == 0) {
//do something    
}
somelist.add(something.getSomethingElse().getField());

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

لاحظ أن هذا سؤال أكاديمي (مدرسة فضولية فقط) بدلا من ذلك العملي.

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

المحلول

افترض أن getSomethingElse() يعرف ب

public SomethingElse getSomethingElse() {
    return this.somethingElse;
}

سيكون اختلاف الأداء ضئيلا (أو صفر إذا كان سيتم إبزيم). ومع ذلك، في الحياة الحقيقية، لا يمكنك دائما التأكد من أن هذا هو الحال - قد يكون هناك بعض المعالجة التي تحدث خلف الكواليس (وليس بالضرورة في الكائن نفسه ولكن، على سبيل المثال، عبر OOP Proxy). لذا فإن توفير النتيجة في المتغير لإمكانية الوصول قد يكون فكرة جيدة.

نصائح أخرى

إنه سيطر ضئيل. لا تهتم بنفسك كثيرا أو ستحدر فريسة للتحسين المبكر. إذا كان طلبك بطيئا، فهذا ليس السبب في ذلك.

هناك اختلاف في تلك المتغيرات الوصول من خلال نتائج Getters في مكالمة طريقة. قد يتمكن JVM من تصور على تحسين طريقة الاتصال بالطريقة في بعض الحالات، لكنها هو مكالمة طريقة.

ومع ذلك، إذا كانت أكبر عنق الزجاجة أو مشكلة أداء في الكود النفقات العامة من طرق الملحقات، أود أن أقول أنك لا تملك الكثير للقلق.

هناك عقوبة في الأداء (والتي قد تكون صغيرة جدا لا يكاد عليها) حتى الآن، قد يتلاشى JVM هذا وجميع المكالمات لتحسين الأداء.

سيكون من الأفضل إذا تركتها الطريقة الثانية.

ليس إذا كان لديك JVM جيدة، مثل نقطة ساخنة من Sun. وسوف يتماشى وتجميع (إلى الرمز الأصلي) The Getters.

يعد استخدام Getters بشكل عام ممارسات جيدة للغاية، كتدبير دفاعي، واختباء المعلومات العامة.

نقطة واحدة لملاحظة إذا كنت تستخدم Java لكتابة تطبيقات Android هنا:http://developer.android.com/training/articles/perf-tips.html#ettersSebeTers.

في لغات أصلية مثل C ++ إنها الممارسة الشائعة لاستخدام Getters (i = getcount ()) بدلا من الوصول إلى الحقل مباشرة (i = mcount). هذه عادة ممتازة ل C ++ وغالبا ما تمارس في لغات أخرى موجهة نحو الكائنات مثل C # و Java، لأن المحول البرمجي عادة ما يتضح عادة الوصول، وإذا كنت بحاجة إلى تقييد أو تصحيح الوصول إلى الحقل يمكنك إضافة الرمز في أي وقت.

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

بدون JIT، الوصول الميداني المباشر حوالي 3x بشكل أسرع من استدعاء الحصول على كتاب تافه. مع JIT (حيث الوصول الميداني المباشر هو رخيصة كما يصل إلى محلي)، الوصول المباشر الوصول إلى 7x أسرع من استدعاء الحصول على الحصول على تافهة.

لاحظ أنه إذا كنت تستخدم Proguard، فيمكنك الحصول على أفضل ما في العالمين لأن Proguard يمكن أن يظرا الملائمين لك.

إذا كانت الطريقة عبارة عن Getter بسيطة مع عدم وجود معالجة، فلا تكون مشكلة. إذا كان ينطوي على حساب واسع النطاق، فلن تفعل العقار ما تريد على أي حال.

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

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

هذه المشاركة تتحدث عن CLI VM بدلا من JVM، ولكن كل منها قادر على القيام بأشياء مماثلة، لذلك أعتقد أنها ذات صلة.

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

  1. توفير الوقت في جيت (ldfld يأخذ وقت معالج أقل ل JIT من call).
  2. خصائص مضمنة حتى في مترجم خط الأساس.
  3. من خلال ضمان كبير أن استخدام نمط الحقول الخاصة / الحقول الخاصة لن يتحمل عقوبة أداء من أي نوع عندما يتم فصل المصحح. (عند إرفاق مصحح الأخطاء، لا يمكنني مضمون الملاءمة.)

ليس لدي شك في أن الأسماء الكبيرة في تكنولوجيات VM تنفذ بالفعل شيئا مشابها ل (وربما أفضل من) هذا في منتجاتها.

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