أسرع طريقة لتكرار مصفوفة في Java:متغير الحلقة مقابل المحسن للبيان [نسخة مكررة]

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

  •  06-07-2019
  •  | 
  •  

سؤال

هذا السؤال لديه بالفعل إجابة هنا:

في Java، هل من الأسرع التكرار عبر المصفوفة بالطريقة القديمة؟

for (int i = 0; i < a.length; i++)
    f(a[i]);

أو باستخدام صيغة أكثر إيجازا،

for (Foo foo : a)
    f(foo);

بالنسبة لقائمة ArrayList، هل الإجابة هي نفسها؟

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

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

المحلول

إذا كنت تقوم بالتكرار عبر مصفوفة، فلا ينبغي أن يكون ذلك مهمًا - فحلقة for المحسنة تستخدم الوصول إلى المصفوفة على أي حال.

على سبيل المثال، خذ بعين الاعتبار هذا الكود:

public static void main(String[] args)
{
    for (String x : args)
    {
        System.out.println(x);
    }
}

عندما تم فك ترجمتها مع javap -c Test نحصل على (ل main طريقة):

public static void main(java.lang.String[]);
  Code:
   0:   aload_0
   1:   astore_1
   2:   aload_1
   3:   arraylength
   4:   istore_2
   5:   iconst_0
   6:   istore_3
   7:   iload_3
   8:   iload_2
   9:   if_icmpge   31
   12:  aload_1
   13:  iload_3
   14:  aaload
   15:  astore  4
   17:  getstatic   #2; //Field java/lang/System.out:Ljava/io/PrintStream;
   20:  aload   4
   22:  invokevirtual   #3; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   25:  iinc    3, 1
   28:  goto    7
   31:  return

الآن قم بتغييره لاستخدام وصول صريح إلى المصفوفة:

public static void main(String[] args)
{
    for (int i = 0; i < args.length; i++)
    {
        System.out.println(args[i]);
    }
}

يتم فك هذا إلى:

public static void main(java.lang.String[]);
  Code:
   0:   iconst_0
   1:   istore_1
   2:   iload_1
   3:   aload_0
   4:   arraylength
   5:   if_icmpge   23
   8:   getstatic   #2; //Field java/lang/System.out:Ljava/io/PrintStream;
   11:  aload_0
   12:  iload_1
   13:  aaload
   14:  invokevirtual   #3; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
   17:  iinc    1, 1
   20:  goto    2
   23:  return

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

اقتراح:إذا كنت تعتقد حقًا أنه قد يحدث فرقًا كبيرًا (وهو ما سيحدث فقط أبدًا افعل ذلك إذا كان نص الحلقة صغيرًا تمامًا) فيجب عليك قياسه باستخدام تطبيقك الحقيقي.هذا هو الوضع الوحيد الذي يهم.

نصائح أخرى

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

ومع ذلك، بالنسبة لقائمة ArrayList لن يكون هناك فرق كبير ولكن القائمة المرتبطة ستكون أكثر كفاءة مع الثانية.

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

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

للحصول على قائمة مرتبطة:

for(ClassOfElement element : listOfElements) {
  System.out.println(element.getValue());
}

تمت الإجابة عليه من قبل:

هل هناك فرق في الأداء بين حلقة for وحلقة لكل حلقة؟

في المصفوفة أو مجموعة RandomAccess، يمكنك الحصول على زيادة طفيفة في السرعة عن طريق القيام بما يلي:

List<Object> list = new ArrayList<Object>();

for (int i=0, d=list.size(); i<d; i++) {
    something(list.get(i));
}

لكنني لن أقلق بشكل عام.لن تُحدث تحسينات مثل هذه فرقًا يزيد عن 0.1% في التعليمات البرمجية الخاصة بك.حاول استدعاء Java باستخدام -البروفيسور لمعرفة أين يقضي الكود الخاص بك وقته بالفعل.

والأسرع من ذلك هو استخدام ParallelArray لإطار عمل fork-join (إذا كان لديك مجموعة بيانات كبيرة بما يكفي).

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