Apa, jika ada, perbedaan kinerja antara dua loop berikut?
for (Object o: objectArrayList) {
o.DoSomething();
}
dan
for (int i=0; i<objectArrayList.size(); i++) {
objectArrayList.get(i).DoSomething();
}
java
performance
for-loop
eflles
sumber
sumber
Jawaban:
Dari Butir 46 di Java Efektif oleh Joshua Bloch:
sumber
Semua loop ini melakukan hal yang persis sama, saya hanya ingin menunjukkan ini sebelum memasukkan dua sen saya.
Pertama, cara klasik perulangan melalui Daftar:
Kedua, cara yang disukai karena lebih sedikit rawan kesalahan (berapa kali ANDA melakukan "oops, mencampur variabel i dan j dalam loop ini dalam loop" hal?).
Ketiga, loop mikro yang dioptimalkan:
Sekarang dua sen aktual: Setidaknya ketika saya menguji ini, yang ketiga adalah tercepat ketika menghitung milidetik pada berapa lama waktu untuk setiap jenis loop dengan operasi sederhana di dalamnya diulang beberapa juta kali - ini menggunakan Java 5 dengan jre1.6u10 pada Windows jika ada yang tertarik.
Walaupun setidaknya tampaknya agar yang ketiga adalah yang tercepat, Anda benar-benar harus bertanya pada diri sendiri apakah Anda ingin mengambil risiko menerapkan optimasi lubang pengintai ini di mana-mana dalam kode pengulangan Anda karena dari apa yang saya lihat, pengulangan aktual bukan t biasanya bagian yang paling memakan waktu dari program nyata (atau mungkin saya hanya bekerja di bidang yang salah, siapa tahu). Dan juga seperti yang saya sebutkan dalam dalih untuk Java untuk-setiap loop (beberapa menyebutnya sebagai loop Iterator dan yang lainnya sebagai for-in loop ) Anda cenderung memukul salah satu bug bodoh tertentu ketika menggunakannya. Dan sebelum memperdebatkan bagaimana ini bahkan bisa lebih cepat daripada yang lain, ingat bahwa javac tidak mengoptimalkan bytecode sama sekali (well, hampir sama sekali toh), itu hanya mengkompilasinya.
Jika Anda ke optimasi mikro dan / atau perangkat lunak Anda menggunakan banyak loop rekursif dan semacamnya maka Anda mungkin tertarik pada tipe loop ketiga. Ingatlah untuk membuat tolok ukur perangkat lunak Anda dengan baik sebelum dan sesudah mengubah for loop Anda harus ke yang aneh ini, dioptimalkan secara mikro.
sumber
get(int)
, yang lain menggunakanIterator
. Pertimbangkan diLinkedList
mana kinerjafor(int i=0;i<strings.size();i++) { /* do something using strings.get(i) */ }
jauh lebih buruk karena melakukan beberapaget(int)
kali.Untuk-setiap loop umumnya harus lebih disukai. Pendekatan "dapatkan" mungkin lebih lambat jika implementasi Daftar yang Anda gunakan tidak mendukung akses acak. Misalnya, jika LinkedList digunakan, Anda akan dikenakan biaya traversal, sedangkan pendekatan untuk masing-masing menggunakan iterator yang melacak posisinya dalam daftar. Informasi lebih lanjut tentang nuansa setiap loop .
Saya pikir artikelnya ada di sini: lokasi baru
Tautan yang ditunjukkan di sini sudah mati.
sumber
Ya, dampak kinerja sebagian besar tidak signifikan, tetapi tidak nol. Jika Anda melihat
RandomAccess
antarmuka JavaDoc :Dan untuk-setiap loop menggunakan versi dengan iterator, jadi
ArrayList
misalnya, untuk-setiap loop tidak tercepat.sumber
Iterable
s, tetapi tidak array. Untuk array digunakan for-loop dengan variabel indeks. Ada informasi tentang ini di JLS .Sayangnya ada perbedaan.
Jika Anda melihat kode byte yang dihasilkan untuk kedua jenis loop, mereka berbeda.
Berikut adalah contoh dari kode sumber Log4j.
Di /log4j-api/src/main/java/org/apache/logging/log4j/MarkerManager.java kita memiliki kelas dalam statis yang disebut Log4jMarker yang mendefinisikan:
Dengan loop standar:
Dengan untuk masing-masing:
Ada apa dengan ITU Oracle?
Saya sudah mencoba ini dengan Java 7 dan 8 pada Windows 7.
sumber
Itu selalu lebih baik untuk menggunakan iterator daripada pengindeksan. Ini karena iterator kemungkinan besar dioptimalkan untuk implementasi Daftar sementara indeks (panggilan get) mungkin tidak. Misalnya LinkedList adalah Daftar tetapi pengindeksan melalui elemen-elemennya akan lebih lambat daripada iterasi menggunakan iterator.
sumber
foreach membuat maksud kode Anda lebih jelas dan yang biasanya lebih disukai daripada peningkatan kecepatan yang sangat kecil - jika ada.
Setiap kali saya melihat loop diindeks saya harus menguraikannya sedikit lebih lama untuk memastikan itu melakukan apa yang saya pikirkan Apakah itu mulai dari nol, apakah itu termasuk atau tidak termasuk titik akhir dll?
Sebagian besar waktu saya tampaknya dihabiskan membaca kode (yang saya tulis atau orang lain tulis) dan kejelasan hampir selalu lebih penting daripada kinerja. Sangat mudah untuk mengabaikan kinerja hari ini karena Hotspot melakukan pekerjaan yang luar biasa.
sumber
Kode berikut:
Memberikan output berikut pada sistem saya:
Saya menjalankan Ubuntu 12.10 alpha dengan pembaruan OracleJDK 1.7 6.
Secara umum HotSpot mengoptimalkan banyak tipuan dan operasi redup sederhana, jadi secara umum Anda tidak perlu khawatir tentang mereka kecuali ada banyak dari mereka di seqence atau mereka sangat bersarang.
Di sisi lain, pengindeksan di LinkedList jauh lebih lambat daripada memanggil iterator berikutnya untuk LinkedList sehingga Anda dapat menghindari kinerja tersebut sambil mempertahankan keterbacaan saat Anda menggunakan iterator (secara eksplisit atau implisit dalam untuk setiap loop).
sumber
Bahkan dengan sesuatu seperti ArrayList atau Vector, di mana "get" adalah pencarian array sederhana, loop kedua masih memiliki overhead tambahan yang tidak dimiliki oleh yang pertama. Saya berharap itu menjadi sedikit lebih lambat dari yang pertama.
sumber
Satu-satunya cara untuk mengetahui dengan pasti adalah dengan membandingkannya, dan bahkan itu tidak sesederhana kedengarannya . Kompiler JIT dapat melakukan hal-hal yang sangat tidak terduga pada kode Anda.
sumber
Berikut adalah analisis singkat tentang perbedaan yang dikeluarkan oleh tim pengembangan Android:
https://www.youtube.com/watch?v=MZOf3pOAM6A
Hasilnya adalah bahwa ada adalah perbedaan, dan dalam lingkungan yang sangat terkendali dengan daftar yang sangat besar itu bisa menjadi perbedaan yang nyata. Dalam pengujian mereka, untuk setiap loop memakan waktu dua kali lebih lama. Namun, pengujian mereka lebih dari daftar array 400.000 bilangan bulat. Perbedaan aktual per elemen dalam array adalah 6 mikrodetik . Saya belum menguji dan mereka tidak mengatakan, tapi saya berharap perbedaannya menjadi sedikit lebih besar menggunakan objek daripada primitif, tetapi bahkan masih kecuali Anda sedang membangun kode perpustakaan di mana Anda tidak tahu skala apa yang akan Anda tanyakan untuk beralih, saya pikir perbedaannya tidak perlu ditekankan.
sumber
Dengan nama variabel
objectArrayList
, saya menganggap itu adalah turunan darijava.util.ArrayList
. Dalam hal ini, perbedaan kinerja tidak akan terlalu terasa.Di sisi lain, jika itu adalah contoh dari
java.util.LinkedList
, pendekatan kedua akan jauh lebih lambat karena operasiList#get(int)
O (n).Jadi pendekatan pertama selalu lebih disukai kecuali indeks dibutuhkan oleh logika dalam loop.
sumber
Keduanya melakukan hal yang sama tetapi untuk penggunaan pemrograman yang mudah dan aman untuk masing-masing, ada kemungkinan rawan kesalahan dalam cara penggunaan kedua.
sumber
Sungguh aneh bahwa tidak ada yang menyebutkan yang jelas - foreach mengalokasikan memori (dalam bentuk iterator), sedangkan normal untuk loop tidak mengalokasikan memori apa pun. Untuk gim di Android, ini merupakan masalah, karena itu berarti pengumpul sampah akan berjalan secara berkala. Dalam gim Anda tidak ingin pengumpul sampah berjalan ... PERNAH. Jadi jangan gunakan foreach loop dalam metode draw (atau render) Anda.
sumber
Jawaban yang diterima menjawab pertanyaan, selain dari kasus ArrayList yang luar biasa ...
Karena sebagian besar pengembang mengandalkan ArrayList (setidaknya saya percaya begitu)
Jadi saya wajib menambahkan jawaban yang benar di sini.
Langsung dari dokumentasi pengembang: -
Enhanced for loop (juga kadang-kadang dikenal sebagai "for-each" loop) dapat digunakan untuk koleksi yang mengimplementasikan antarmuka Iterable dan untuk array. Dengan koleksi, iterator dialokasikan untuk melakukan panggilan antarmuka ke hasNext () dan next (). Dengan ArrayList, loop terhitung tulisan tangan sekitar 3x lebih cepat (dengan atau tanpa JIT), tetapi untuk koleksi lain, sintaks loop yang ditingkatkan untuk akan sama persis dengan penggunaan iterator eksplisit.
Ada beberapa alternatif untuk iterasi melalui array:
zero () paling lambat, karena JIT belum dapat mengoptimalkan biaya untuk mendapatkan panjang array satu kali untuk setiap iterasi melalui loop.
satu () lebih cepat. Ini menarik semuanya ke dalam variabel lokal, menghindari pencarian. Hanya panjang array yang menawarkan manfaat kinerja.
dua () adalah yang tercepat untuk perangkat tanpa JIT, dan tidak dapat dibedakan dari satu () untuk perangkat dengan JIT. Ini menggunakan sintaks loop ditingkatkan untuk diperkenalkan di versi 1.5 dari bahasa pemrograman Java.
Jadi, Anda harus menggunakan loop yang ditingkatkan untuk secara default, tetapi pertimbangkan loop terhitung tulisan tangan untuk iterasi ArrayList yang kritis terhadap kinerja.
sumber
Ya,
for-each
varian lebih cepat dari biasanyaindex-based-for-loop
.for-each
penggunaan varianiterator
. Jadi traverse lebih cepat darifor
loop normal yang berbasis indeks.Ini karena
iterator
dioptimalkan untuk melintasi, karena menunjuk tepat sebelum elemen berikutnya dan tepat setelah elemen sebelumnya . Salah satu alasan untuk menjadiindex-based-for-loop
lambat adalah itu, ia harus menghitung dan pindah ke posisi elemen setiap kali yang tidak denganiterator
.sumber
sumber