Di .NET, loop mana yang berjalan lebih cepat, 'untuk' atau 'foreach'?


345

Di C # / VB.NET / .NET, loop mana yang berjalan lebih cepat, foratau foreach?

Sejak saya membaca bahwa forlingkaran bekerja lebih cepat dari foreachlingkaran waktu yang lalu saya diasumsikan itu berdiri berlaku untuk semua koleksi, koleksi generik, semua array, dll

Saya menjelajahi Google dan menemukan beberapa artikel, tetapi kebanyakan dari mereka tidak meyakinkan (baca komentar pada artikel) dan terbuka.

Apa yang ideal adalah membuat setiap skenario dicantumkan dan solusi terbaik untuk hal yang sama.

Misalnya (hanya contoh bagaimana seharusnya):

  1. untuk iterasi array 1000+ string - forlebih baik daripadaforeach
  2. untuk iterasi dari IListstring (non generik) - foreachlebih baik daripadafor

Beberapa referensi ditemukan di web untuk hal yang sama:

  1. Artikel asli agung lama oleh Emmanuel Schanzer
  2. CodeEject FOREACH Vs. UNTUK
  3. Blog - Ke foreachatau tidak foreach, itulah pertanyaannya
  4. Forum ASP.NET - NET 1.1 C # forvsforeach

[Sunting]

Terlepas dari aspek keterbacaannya, saya benar-benar tertarik pada fakta dan angka. Ada beberapa aplikasi di mana jarak terakhir dari optimasi kinerja tidak menjadi masalah.


3
Perbedaannya masih ada. Array khususnya harus sama cepat di bawah foreach, tetapi untuk semua yang lain, loop polos lebih cepat. Tentu saja, sebagian besar waktu, ini tidak akan membuat perbedaan, dan tentu saja, kompiler JIT yang pintar secara teori dapat menghilangkan perbedaan.
jalf

3
Tanpa konteks, saya tidak bisa tahu persis apa yang Anda lakukan, tetapi apa yang terjadi ketika Anda menemukan array yang terisi sebagian?
Chris Cudmore

6
Omong-omong, 2 juta hit / bulan bukanlah hal yang menakutkan. Rata-rata kurang dari hit per detik.
Mehrdad Afshari

37
Catatan Penting : Pertanyaan ini kemarin digabungkan dengan pertanyaan yang sama sekali tidak terkait tentang dipaksa untuk digunakan foreachalih-alih fordalam C #. Jika Anda melihat jawaban di sini tidak masuk akal sama sekali, itu sebabnya. Salahkan moderator, bukan jawaban yang malang.
TED

7
@ TED Oh saya bertanya-tanya dari mana semua "bos Anda idiot" berkomentar dari mana, terima kasih
Gaspa79

Jawaban:


350

Patrick Smacchia membuat blog tentang ini bulan lalu, dengan kesimpulan sebagai berikut:

  • untuk loop pada List sedikit lebih dari 2 kali lebih murah daripada foreach loop pada List.
  • Looping pada array sekitar 2 kali lebih murah daripada looping on List.
  • Sebagai konsekuensinya, perulangan menggunakan array untuk 5 kali lebih murah daripada perulangan pada daftar menggunakan foreach (yang saya percaya, adalah apa yang kita semua lakukan).

130
Namun, jangan pernah lupa: "Optimalisasi prematur adalah akar dari semua kejahatan."
Oorang

18
@ Hardwareguy: Setelah Anda tahu bahwa untuk hampir secara cepat terasa lebih cepat, mengapa Anda tidak mulai menggunakannya secara umum? Tidak perlu waktu ekstra.
DevinB

47
@devinb, menggunakan "for" lebih sulit daripada menggunakan "foreach" karena ia menambahkan kode, variabel lain, kondisi yang perlu Anda periksa, dll. Berapa kali Anda melihat kesalahan off-by-one dalam loop "foreach" ?
tster

35
@Hardwareguy, biarkan saya melihat apakah saya benar. Dibutuhkan 5 kali lebih lama untuk mengulang daftar dengan foreachdaripada yang diperlukan untuk mengulang melalui array dengan for, dan Anda memanggil itu tidak signifikan? Perbedaan kinerja semacam itu mungkin penting bagi aplikasi Anda, dan mungkin tidak, tetapi saya tidak akan mengabaikannya begitu saja.
Robert Harvey

44
Membaca melalui posting blog sepertinya tes dijalankan di Debug dan tidak Lepaskan sehingga mungkin memiliki faktor. Selain itu perbedaannya hanya khusus untuk overhead loop. Itu tidak mempengaruhi waktu untuk mengeksekusi tubuh loop sama sekali yang kebanyakan kasus jauh lebih lama daripada waktu yang diperlukan untuk pindah ke elemen berikutnya dari daftar. Ini informasi yang baik untuk mengetahui kapan Anda telah mengidentifikasi bahwa ada masalah dan Anda telah mengukur perbedaan dalam aplikasi Anda secara khusus dan ada peningkatan yang nyata tetapi jelas bukan saran umum untuk menghapus semua foreach.
Davy8

164

Pertama, klaim balik terhadap jawaban Dmitry (sekarang dihapus) . Untuk array, kompiler C # memancarkan sebagian besar kode yang sama foreachseperti untuk forloop setara . Itu menjelaskan mengapa untuk tolok ukur ini, hasilnya pada dasarnya sama:

using System;
using System.Diagnostics;
using System.Linq;

class Test
{
    const int Size = 1000000;
    const int Iterations = 10000;

    static void Main()
    {
        double[] data = new double[Size];
        Random rng = new Random();
        for (int i=0; i < data.Length; i++)
        {
            data[i] = rng.NextDouble();
        }

        double correctSum = data.Sum();

        Stopwatch sw = Stopwatch.StartNew();
        for (int i=0; i < Iterations; i++)
        {
            double sum = 0;
            for (int j=0; j < data.Length; j++)
            {
                sum += data[j];
            }
            if (Math.Abs(sum-correctSum) > 0.1)
            {
                Console.WriteLine("Summation failed");
                return;
            }
        }
        sw.Stop();
        Console.WriteLine("For loop: {0}", sw.ElapsedMilliseconds);

        sw = Stopwatch.StartNew();
        for (int i=0; i < Iterations; i++)
        {
            double sum = 0;
            foreach (double d in data)
            {
                sum += d;
            }
            if (Math.Abs(sum-correctSum) > 0.1)
            {
                Console.WriteLine("Summation failed");
                return;
            }
        }
        sw.Stop();
        Console.WriteLine("Foreach loop: {0}", sw.ElapsedMilliseconds);
    }
}

Hasil:

For loop: 16638
Foreach loop: 16529

Selanjutnya, validasi bahwa poin Greg tentang jenis koleksi menjadi penting - ubah array menjadi List<double>di atas, dan Anda mendapatkan hasil yang sangat berbeda. Tidak hanya secara signifikan lebih lambat secara umum, tetapi juga menjadi lebih lambat secara signifikan daripada mengakses dengan indeks. Karena itu, saya masih hampir selalu lebih suka foreach untuk loop di mana ia membuat kode lebih sederhana - karena keterbacaan hampir selalu penting, sedangkan mikro-optimasi jarang.


"ubah larik menjadi Daftar <double> di atas, dan Anda mendapatkan hasil yang sangat berbeda" Sangat menarik, saya tidak memikirkan hal itu
johnc

5
Mengingat perbedaan aneh di hasil antara tes saya dan tolok ukur orang lain, saya pikir ini akan jasa posting blog ...
Jon Skeet

1
Mana yang hampir selalu Anda sukai antara array dan List<T>? Apakah keterbacaan truf optimasi mikro dalam kasus itu juga?
JohnB

12
@ JohnB: Yup - Saya hampir selalu lebih suka List<T>daripada array. Pengecualiannya adalah char[]dan byte[]yang lebih sering diperlakukan sebagai "potongan" data daripada koleksi normal.
Jon Skeet

Luar biasa, saya mendapatkan perbedaan yang lebih agresif pada mesin saya, hampir 10% mendukung pendahuluan pada array sederhana. Saya menduga liar bahwa ini semua berasal dari jitter tidak perlu khawatir tentang variabel tambahan, cek terikat, dll. Akan sangat menarik jika seseorang memiliki penjelasan mendalam tentang ini.
Tamir Daniely

162

foreachloop menunjukkan niat yang lebih spesifik daripada forloop .

Menggunakan foreachloop menunjukkan kepada siapa pun yang menggunakan kode Anda bahwa Anda berencana untuk melakukan sesuatu kepada setiap anggota koleksi terlepas dari tempatnya dalam koleksi. Ini juga menunjukkan Anda tidak mengubah koleksi asli (dan melempar pengecualian jika Anda mencoba).

Keuntungan lain foreachadalah bahwa ia bekerja pada apa pun IEnumerable, di mana forhanya masuk akal IList, di mana setiap elemen sebenarnya memiliki indeks.

Namun, jika Anda perlu menggunakan indeks suatu elemen, maka tentu saja Anda harus diizinkan menggunakan forloop. Tetapi jika Anda tidak perlu menggunakan indeks, memilikinya hanya akan mengacaukan kode Anda.

Tidak ada implikasi kinerja yang signifikan sejauh yang saya ketahui. Pada tahap tertentu di masa depan, mungkin lebih mudah untuk mengadaptasi kode yang digunakan foreachuntuk berjalan pada banyak core, tapi itu bukan sesuatu yang perlu dikhawatirkan saat ini.


23
ctford: Tidak. Kompiler tentu tidak dapat menyusun ulang elemen di foreach. foreachsama sekali tidak terkait dengan pemrograman fungsional. Ini benar - benar paradigma penting pemrograman. Anda salah menghubungkan hal-hal yang terjadi di TPL dan PLINQ ke foreach.
Mehrdad Afshari

13
@ BlueTrin: Ini tentu saja menjamin pemesanan (C # spec bagian 8.8.4 secara resmi didefinisikan foreachsebagai setara dengan whileloop). Saya rasa saya tahu yang dimaksud dengan @ctford. Pustaka paralel tugas memungkinkan koleksi yang mendasarinya untuk menyediakan elemen-elemen dalam urutan acak (dengan memanggil .AsParallelenumerable). foreachtidak melakukan apa pun di sini dan tubuh loop dijalankan pada satu utas . Satu-satunya hal yang diparalelkan adalah pembuatan urutan.
Mehrdad Afshari

6
Enumerable. Pilih memiliki kelebihan yang memungkinkan Anda mendapatkan indeks item, sehingga bahkan kebutuhan untuk indeks tidak diamanatkan menggunakan untuk. Lihat msdn.microsoft.com/en-us/library/bb534869.aspx
TrueWill

5
ForEach berguna untuk keterbacaan dan menghemat pengetikan. Biaya menjadi masalah; mengubah 2 atau 3 untuk-loop dalam UI perancang dokumen yang saya buat, dari (untuk setiap objek dalam daftar) menjadi (untuk i = 0 ke list.count-1) mengurangi waktu respons dari 2-3 detik per edit menjadi sekitar. 5 detik per edit pada dokumen kecil yang hanya diulang beberapa ratus objek. Sekarang bahkan untuk dokumen besar, tidak ada peningkatan waktu untuk mengulang semua. Saya tidak tahu bagaimana ini terjadi. Yang saya tahu adalah bahwa alternatifnya adalah skema yang rumit untuk hanya mengulang bagian dari objek. Saya akan mengambil perubahan 5 menit setiap hari! - bukan optimasi mikro.
FastAl

5
@FastAl Perbedaan antara foreachdan forkinerja untuk daftar normal adalah sepersekian detik untuk iterasi lebih dari jutaan item sehingga masalah Anda tentu tidak terkait langsung dengan kinerja foreach, setidaknya tidak untuk beberapa ratus objek. Kedengarannya seperti implementasi enumerator yang rusak di daftar apa pun yang Anda gunakan.
Mike Marynowski

53

Setiap kali ada argumen atas kinerja, Anda hanya perlu menulis tes kecil sehingga Anda dapat menggunakan hasil kuantitatif untuk mendukung kasus Anda.

Gunakan kelas StopWatch dan ulangi sesuatu beberapa juta kali, untuk akurasi. (Ini mungkin sulit tanpa loop):

using System.Diagnostics;
//...
Stopwatch sw = new Stopwatch()
sw.Start()
for(int i = 0; i < 1000000;i ++)
{
    //do whatever it is you need to time
}
sw.Stop();
//print out sw.ElapsedMilliseconds

Semoga hasil-hasil ini menunjukkan bahwa perbedaannya dapat diabaikan, dan Anda mungkin juga melakukan apa saja yang menghasilkan kode yang paling dapat dipertahankan.


13
Tetapi Anda tidak dapat membandingkan kinerja for foreach dan foreach. Mereka seharusnya digunakan dalam situasi yang berbeda.
Michael Krelin - hacker

7
Saya setuju dengan Anda Michael, Anda tidak boleh memilih mana yang akan digunakan berdasarkan kinerja - Anda harus memilih yang paling masuk akal! Tapi jika bos Anda mengatakan "Jangan gunakan untuk karena itu lebih lambat dari foreach" maka ini adalah satu-satunya cara untuk meyakinkan dia bahwa perbedaan diabaikan
Rob Fonseca-Ensor

"(Ini mungkin sulit tanpa loop untuk)" Atau Anda dapat menggunakan loop sementara.
jonescb

49

Itu akan selalu dekat. Untuk sebuah array, kadang for - kadang sedikit lebih cepat, tetapi foreachlebih ekspresif, dan menawarkan LINQ, dll. Secara umum, tetap dengan foreach.

Selain itu, foreachdapat dioptimalkan dalam beberapa skenario. Misalnya, daftar tertaut mungkin mengerikan oleh pengindeks, tetapi mungkin cepat foreach. Sebenarnya, standar LinkedList<T>bahkan tidak menawarkan pengindeks karena alasan ini.


Jadi LinkedList<T>maksudmu lebih ramping dari itu List<T>? Dan jika saya akan selalu menggunakan foreach(bukannya for), saya lebih baik menggunakan LinkedList<T>?
JohnB

2
@ JohnB - tidak lebih ramping; hanya berbeda. Misalnya, setiap node dalam daftar tertaut memiliki referensi tambahan yang tidak diperlukan untuk array datar (yang juga mendukung List<T>). Lebih dari itu lebih murah untuk memasukkan / menghapus .
Marc Gravell

36

Dugaan saya adalah bahwa hal itu mungkin tidak akan signifikan dalam 99% kasus, jadi mengapa Anda memilih yang lebih cepat daripada yang paling tepat (seperti yang paling mudah dipahami / dipelihara)?


6
@ mewah, Jika Anda benar-benar membuat profil kode Anda, Anda tidak perlu menebak yang 20% ​​harus secepat mungkin. Anda mungkin juga akan menemukan bahwa jumlah loop aktual yang harus cepat jauh lebih rendah. Lebih jauh lagi, apakah Anda benar-benar mengatakan bahwa tindakan pengulangan adalah tempat Anda menghabiskan waktu, berbeda dengan apa yang sebenarnya Anda lakukan dalam pengulangan itu?
tster

32

Tidak mungkin ada perbedaan kinerja yang sangat besar di antara keduanya. Seperti biasa, ketika dihadapkan dengan "mana yang lebih cepat?" pertanyaan, Anda harus selalu berpikir "Saya bisa mengukur ini."

Tulis dua loop yang melakukan hal yang sama di tubuh loop, jalankan dan beri waktu keduanya, dan lihat perbedaan kecepatannya. Lakukan ini dengan tubuh yang hampir kosong, dan tubuh melingkar yang mirip dengan apa yang sebenarnya akan Anda lakukan. Coba juga dengan jenis koleksi yang Anda gunakan, karena berbagai jenis koleksi dapat memiliki karakteristik kinerja yang berbeda.


32

Ada alasan yang sangat bagus untuk memilih foreach loop daripada forloop. Jika Anda dapat menggunakan foreachloop, bos Anda benar bahwa Anda harus melakukannya.

Namun, tidak setiap iterasi hanya melalui daftar secara berurutan. Jika dia melarang , ya itu salah.

Jika saya adalah Anda, apa yang akan saya lakukan adalah mengubah semua alami Anda untuk loop menjadi rekursi . Itu akan mengajarinya, dan itu juga latihan mental yang baik untuk Anda.


Bagaimana rekursi dibandingkan dengan forloop dan foreachloop kinerja-bijaksana?
JohnB

Tergantung. Jika Anda menggunakan rekursi ekor dan kompiler Anda cukup pintar untuk melihat, itu bisa identik. OTOH: Jika tidak dan Anda melakukan sesuatu yang bodoh seperti melewatkan banyak data tidak sehat (tidak berubah) sebagai parameter atau mendeklarasikan struktur besar di stack sebagai penduduk lokal, itu bisa sangat lambat (atau bahkan kehabisan RAM).
TED

Ahhh Saya mengerti mengapa Anda menanyakan hal itu sekarang. Jawaban ini mengarah ke pertanyaan yang sama sekali berbeda. Entah mengapa, Jonathan Sampson menggabungkan keduanya kemarin. Dia seharusnya tidak melakukan itu. Jawaban yang digabungkan tidak akan masuk akal di sini sama sekali.
TED

18

Jeffrey Richter di TechEd 2005:

"Saya datang untuk belajar selama bertahun-tahun bahwa kompiler C # pada dasarnya adalah pembohong bagi saya." .. "Itu bohong tentang banyak hal." .. "Seperti ketika Anda melakukan loop foreach ..." .. "... itu adalah satu baris kecil kode yang Anda tulis, tetapi apa yang dikompilasi oleh kompiler C # untuk melakukan hal itu sangat fenomenal. coba / akhirnya blokir di sana, di dalam blok akhirnya ia melempar variabel Anda ke antarmuka IDisposable, dan jika pemain berhasil memanggil metode Buang di dalamnya, di dalam loop itu memanggil properti saat ini dan metode MoveNext berulang kali di dalam loop, objek sedang dibuat di bawah selimut. Banyak orang menggunakan foreach karena sangat mudah coding, sangat mudah dilakukan .. ".." foreach tidak terlalu baik dalam hal kinerja,

Siaran Web Berdasarkan Permintaan: http://msevents.microsoft.com/CUI/WebCastEventDetails.aspx?EventID=1032292286&EventCategory=3&culture=en-US&CountryCode=US


12

Ini konyol. Tidak ada alasan kuat untuk melarang perulangan, kinerja-bijaksana atau lainnya.

Lihat blog Jon Skeet untuk benchmark kinerja dan argumen lainnya.


2
Tautan yang diperbarui: codeblog.jonskeet.uk/2009/01/29/…
Matt

Konstruksi loop yang lebih cepat tergantung pada apa yang Anda butuhkan untuk beralih. Blog lain yang menandai beberapa iterasi pada berbagai jenis objek , seperti DataRows dan objek khusus. Ini juga mencakup kinerja konstruksi loop Sementara dan bukan hanya konstruksi loop for dan foreach.
Free Coder 24

11

Dalam kasus di mana Anda bekerja dengan koleksi objek, foreachlebih baik, tetapi jika Anda menambah angka, satu forloop lebih baik.

Perhatikan bahwa dalam kasus terakhir, Anda dapat melakukan sesuatu seperti:

foreach (int i in Enumerable.Range(1, 10))...

Tetapi tentu saja tidak berkinerja lebih baik, itu sebenarnya memiliki kinerja yang lebih buruk dibandingkan dengan for.


"Lebih baik" masih bisa diperdebatkan: Lebih lambat dan debugger dnspy ​​tidak akan masuk ke C # foreach (meskipun debugger VS2017 akan). Terkadang lebih mudah dibaca tetapi jika Anda mendukung bahasa tanpa itu, itu bisa mengganggu.
Zeek2

10

Ini akan menyelamatkan Anda:

public IEnumerator<int> For(int start, int end, int step) {
    int n = start;
    while (n <= end) {
        yield n;
        n += step;
    }
}

Menggunakan:

foreach (int n in For(1, 200, 4)) {
    Console.WriteLine(n);
}

Untuk kemenangan yang lebih besar, Anda dapat menggunakan tiga delegasi sebagai parameter.


1
Satu perbedaan kecil adalah bahwa forloop biasanya ditulis untuk mengecualikan akhir rentang (misalnya 0 <= i < 10). Parallel.Forjuga melakukan itu agar mudah dipertukarkan dengan forloop umum .
Groo

9

Anda dapat membacanya di Deep .NET - bagian 1 Iteration

itu mencakup hasil (tanpa inisialisasi pertama) dari kode sumber .NET sampai ke pembongkaran.

misalnya - Iterasi Array dengan loop foreach: masukkan deskripsi gambar di sini

dan - daftar iterasi dengan foreach loop: masukkan deskripsi gambar di sini

dan hasil akhirnya: masukkan deskripsi gambar di sini

masukkan deskripsi gambar di sini


8

Perbedaan kecepatan dalam a for- dan foreach-loop kecil ketika Anda mengulangi struktur umum seperti array, daftar, dll, dan melakukan LINQkueri atas koleksi hampir selalu sedikit lebih lambat, meskipun lebih baik untuk menulis! Seperti yang dikatakan poster-poster lain, lebih baik ekspresif daripada milidetik kinerja ekstra.

Apa yang belum dikatakan sejauh ini adalah bahwa ketika sebuah foreachloop dikompilasi, ia dioptimalkan oleh kompiler berdasarkan pada koleksi yang berulang-ulang. Itu berarti bahwa ketika Anda tidak yakin loop mana yang harus digunakan, Anda harus menggunakan foreachloop - itu akan menghasilkan loop terbaik untuk Anda ketika akan dikompilasi. Lebih mudah dibaca juga.

Keuntungan utama lainnya dengan foreachloop adalah bahwa jika implementasi koleksi Anda berubah (dari int arrayke List<int>misalnya) maka foreachloop Anda tidak akan memerlukan perubahan kode:

foreach (int i in myCollection)

Di atas adalah sama, apa pun jenis koleksi Anda, sedangkan di forloop Anda , berikut ini tidak akan membangun jika Anda berubah myCollectiondari suatu arrayke List:

for (int i = 0; i < myCollection.Length, i++)

7

"Apakah ada argumen yang bisa saya gunakan untuk membantu saya meyakinkannya bahwa for loop dapat diterima untuk digunakan?"

Tidak, jika bos Anda melakukan manajemen mikro hingga memberi tahu Anda apa bahasa pemrograman yang harus digunakan, benar-benar tidak ada yang bisa Anda katakan. Maaf.


7

Mungkin tergantung pada jenis koleksi yang Anda hitung dan implementasi pengindeksnya. Namun secara umum, menggunakan foreachcenderung menjadi pendekatan yang lebih baik.

Juga, itu akan bekerja dengan apa pun IEnumerable- bukan hanya hal-hal dengan pengindeks.


7

Ini memiliki dua jawaban yang sama dengan sebagian besar pertanyaan "yang lebih cepat":

1) Jika Anda tidak mengukur, Anda tidak tahu.

2) (Karena ...) Itu tergantung.

Tergantung pada seberapa mahal metode "MoveNext ()", relatif terhadap seberapa mahal metode "ini [indeks]", untuk tipe (atau tipe) dari IEnumerable yang akan Anda ulangi.

Kata kunci "foreach" adalah kependekan dari serangkaian operasi - ia memanggil GetEnumerator () satu kali di IEnumerable, ia memanggil MoveNext () sekali per iterasi, ia melakukan pengecekan beberapa jenis, dan seterusnya. Hal yang paling mungkin memengaruhi pengukuran kinerja adalah biaya MoveNext () karena itu akan dipanggil O (N) kali. Mungkin murah, tapi mungkin juga tidak.

Kata kunci "untuk" terlihat lebih dapat diprediksi, tetapi di dalam sebagian besar loop "untuk" Anda akan menemukan sesuatu seperti "koleksi [indeks]". Ini terlihat seperti operasi pengindeksan array sederhana, tetapi sebenarnya adalah pemanggilan metode, yang biayanya sepenuhnya bergantung pada sifat koleksi yang Anda ulangi. Mungkin murah, tapi mungkin juga tidak.

Jika struktur yang mendasari koleksi pada dasarnya adalah daftar tertaut, MoveNext murah, tetapi pengindeks mungkin memiliki biaya O (N), membuat biaya sebenarnya untuk loop "untuk" O (N * N).


6

Setiap konstruksi bahasa memiliki waktu dan tempat yang tepat untuk penggunaan. Ada alasan mengapa bahasa C # memiliki empat pernyataan iterasi yang terpisah - masing-masing ada untuk tujuan tertentu, dan memiliki penggunaan yang sesuai.

Saya sarankan duduk dengan bos Anda dan mencoba menjelaskan secara rasional mengapa forloop memiliki tujuan. Ada kalanya forblok iterasi lebih jelas menggambarkan algoritma daripada foreachiterasi. Ketika ini benar, maka tepat untuk menggunakannya.

Saya juga menunjukkan kepada atasan Anda - Performa tidak, dan seharusnya tidak menjadi masalah dengan cara praktis - ini lebih merupakan masalah ekspresi algoritma dengan cara yang ringkas, bermakna, dapat dipertahankan. Optimalisasi mikro seperti ini melewatkan titik optimalisasi kinerja sepenuhnya, karena setiap manfaat kinerja nyata akan datang dari desain ulang dan refactoring algoritmik, bukan restrukturisasi loop.

Jika, setelah diskusi rasional, masih ada pandangan otoriter ini, terserah Anda bagaimana melanjutkan. Secara pribadi, saya tidak akan senang bekerja di lingkungan di mana pemikiran rasional tidak disarankan, dan akan mempertimbangkan pindah ke posisi lain di bawah majikan yang berbeda. Namun, saya sangat menyarankan diskusi sebelum menjadi kesal - mungkin ada kesalahpahaman sederhana di tempat.


5

Ini adalah apa yang Anda lakukan di dalam loop yang memengaruhi kinerja, bukan konstruk looping aktual (dengan asumsi case Anda non-trivial).


5

Apakah forlebih cepat daripada foreachbenar-benar selain itu intinya. Saya sangat ragu bahwa memilih satu di antara yang lain akan membuat dampak yang signifikan pada kinerja Anda.

Cara terbaik untuk mengoptimalkan aplikasi Anda adalah melalui profil kode aktual. Itu akan menunjukkan metode yang paling banyak menghitung waktu kerja /. Optimalkan itu dulu. Jika kinerja masih tidak dapat diterima, ulangi prosedur.

Sebagai aturan umum saya akan merekomendasikan untuk menjauh dari optimasi mikro karena mereka jarang akan menghasilkan keuntungan yang signifikan. Satu-satunya pengecualian adalah ketika mengoptimalkan jalur panas teridentifikasi (yaitu jika profil Anda mengidentifikasi beberapa metode yang sangat digunakan, mungkin masuk akal untuk mengoptimalkannya secara luas).


Jika satu-satunya jenis optimasi yang perlu saya lakukan dalam proyek yang saya kerjakan adalah optimasi mikro, saya akan senang. Sayangnya, ini tidak pernah terjadi.
Yannick Motton

2
forsedikit lebih cepat dari foreach. Saya benar-benar keberatan dengan pernyataan ini. Itu benar-benar tergantung pada koleksi yang mendasarinya. Jika kelas daftar tertaut menyediakan pengindeks dengan parameter integer, saya akan berharap menggunakan forloop di atasnya menjadi O (n ^ 2) sementara foreachdiharapkan menjadi O (n).
Mehrdad Afshari

@Merhdad: Sebenarnya itu adalah poin yang bagus. Saya hanya berpikir tentang kasus reguler pengindeksan daftar (yaitu array). Saya akan reword untuk mencerminkan itu. Terima kasih.
Brian Rasmussen

@Mehrdad Afshari: Mengindeks koleksi dengan integer mungkin jauh lebih lambat daripada menghitungnya. Tapi Anda sebenarnya membandingkan menggunakan for dan pencarian pengindeksan untuk menggunakan foreachdengan sendirinya. Saya pikir jawaban @Brian Rasmussen benar bahwa, selain dari penggunaan dengan koleksi, forakan selalu sedikit lebih cepat daripada foreach. Namun, forditambah pencarian koleksi akan selalu lebih lambat daripada foreachdengan sendirinya.
Daniel Pryden

@Aniel: Entah Anda memiliki array biasa, yang keduanya akan menghasilkan kode identik, atau ada pengindeks yang terlibat ketika Anda menggunakan forpernyataan. forLoop biasa dengan variabel kontrol integer tidak sebanding dengan foreach, jadi itu keluar. Saya mengerti apa artinya @Brian dan itu benar seperti yang Anda katakan tetapi jawabannya bisa menyesatkan. Re: poin terakhir Anda: tidak, sebenarnya, forover List<T>masih lebih cepat dari foreach.
Mehrdad Afshari

4

Keduanya akan berjalan dengan cara yang hampir persis sama. Tulis beberapa kode untuk menggunakan keduanya, lalu tunjukkan padanya IL. Ini harus menunjukkan perhitungan yang sebanding, yang berarti tidak ada perbedaan dalam kinerja.


Kompiler mengenali setiap loop yang digunakan pada array / ILIST dll dan mengubahnya menjadi untuk loop.
Callum Rogers

3
Tunjukkan padanya baris bukti yang tidak dapat dimengerti bahwa itu OK dan minta buktinya bahwa itu tidak masalah.
cjk

3

karena memiliki logika yang lebih sederhana untuk diimplementasikan sehingga lebih cepat daripada foreach.


3

Kecuali Anda sedang dalam proses optimasi kecepatan tertentu, saya akan mengatakan menggunakan metode apa pun yang menghasilkan kode termudah untuk membaca dan memelihara.

Jika iterator sudah diatur, seperti dengan salah satu kelas koleksi, maka foreach adalah pilihan yang mudah dan bagus. Dan jika rentang integer yang Anda iterasi, maka untuk mungkin lebih bersih.



3

Dalam kebanyakan kasus tidak ada perbedaan.

Biasanya Anda selalu harus menggunakan foreach ketika Anda tidak memiliki indeks numerik eksplisit, dan Anda selalu harus menggunakan ketika Anda tidak benar-benar memiliki koleksi iterable (misalnya iterasi di atas grid array dua dimensi dalam segitiga atas) . Ada beberapa kasus di mana Anda punya pilihan.

Orang bisa berpendapat bahwa untuk loop bisa sedikit lebih sulit untuk dipertahankan jika angka ajaib mulai muncul dalam kode. Anda seharusnya merasa kesal karena tidak dapat menggunakan for for loop dan harus membuat koleksi atau menggunakan lambda untuk membangun subkoleksi alih-alih hanya karena untuk loop telah dilarang.


3

Tampaknya agak aneh untuk sepenuhnya melarang penggunaan sesuatu seperti for loop.

Ada artikel yang menarik di sini yang membahas banyak perbedaan kinerja antara kedua loop.

Saya akan mengatakan secara pribadi saya menemukan foreach sedikit lebih mudah dibaca untuk loop tetapi Anda harus menggunakan yang terbaik untuk pekerjaan di tangan dan tidak harus menulis kode ekstra panjang untuk menyertakan foreach loop jika for for loop lebih tepat.


Kutipan penting dari artikel yang Anda tautkan ke: "... jika Anda berencana untuk menulis kode kinerja tinggi yang bukan untuk koleksi, gunakan untuk loop. Bahkan untuk koleksi, foreach mungkin terlihat berguna saat digunakan, tetapi itu tidak efisien."
NickFitz

3

Saya menemukan foreachloop yang iterasi melalui List lebih cepat . Lihat hasil pengujian saya di bawah ini. Dalam kode di bawah ini saya mengulangi arrayukuran 100, 10.000 dan 100000 secara terpisah menggunakan fordan foreachloop untuk mengukur waktu.

masukkan deskripsi gambar di sini

private static void MeasureTime()
    {
        var array = new int[10000];
        var list = array.ToList();
        Console.WriteLine("Array size: {0}", array.Length);

        Console.WriteLine("Array For loop ......");
        var stopWatch = Stopwatch.StartNew();
        for (int i = 0; i < array.Length; i++)
        {
            Thread.Sleep(1);
        }
        stopWatch.Stop();
        Console.WriteLine("Time take to run the for loop is {0} millisecond", stopWatch.ElapsedMilliseconds);

        Console.WriteLine(" ");
        Console.WriteLine("Array Foreach loop ......");
        var stopWatch1 = Stopwatch.StartNew();
        foreach (var item in array)
        {
            Thread.Sleep(1);
        }
        stopWatch1.Stop();
        Console.WriteLine("Time take to run the foreach loop is {0} millisecond", stopWatch1.ElapsedMilliseconds);

        Console.WriteLine(" ");
        Console.WriteLine("List For loop ......");
        var stopWatch2 = Stopwatch.StartNew();
        for (int i = 0; i < list.Count; i++)
        {
            Thread.Sleep(1);
        }
        stopWatch2.Stop();
        Console.WriteLine("Time take to run the for loop is {0} millisecond", stopWatch2.ElapsedMilliseconds);

        Console.WriteLine(" ");
        Console.WriteLine("List Foreach loop ......");
        var stopWatch3 = Stopwatch.StartNew();
        foreach (var item in list)
        {
            Thread.Sleep(1);
        }
        stopWatch3.Stop();
        Console.WriteLine("Time take to run the foreach loop is {0} millisecond", stopWatch3.ElapsedMilliseconds);
    }

DIPERBARUI

Setelah saran @jgauffin saya menggunakan kode @johnskeet dan menemukan bahwa forloop dengan arraylebih cepat daripada mengikuti,

  • Lingkaran depan dengan array.
  • Untuk loop dengan daftar.
  • Lingkaran depan dengan daftar.

Lihat hasil tes dan kode saya di bawah ini,

masukkan deskripsi gambar di sini

private static void MeasureNewTime()
    {
        var data = new double[Size];
        var rng = new Random();
        for (int i = 0; i < data.Length; i++)
        {
            data[i] = rng.NextDouble();
        }
        Console.WriteLine("Lenght of array: {0}", data.Length);
        Console.WriteLine("No. of iteration: {0}", Iterations);
        Console.WriteLine(" ");
        double correctSum = data.Sum();

        Stopwatch sw = Stopwatch.StartNew();
        for (int i = 0; i < Iterations; i++)
        {
            double sum = 0;
            for (int j = 0; j < data.Length; j++)
            {
                sum += data[j];
            }
            if (Math.Abs(sum - correctSum) > 0.1)
            {
                Console.WriteLine("Summation failed");
                return;
            }
        }
        sw.Stop();
        Console.WriteLine("For loop with Array: {0}", sw.ElapsedMilliseconds);

        sw = Stopwatch.StartNew();
        for (var i = 0; i < Iterations; i++)
        {
            double sum = 0;
            foreach (double d in data)
            {
                sum += d;
            }
            if (Math.Abs(sum - correctSum) > 0.1)
            {
                Console.WriteLine("Summation failed");
                return;
            }
        }
        sw.Stop();
        Console.WriteLine("Foreach loop with Array: {0}", sw.ElapsedMilliseconds);
        Console.WriteLine(" ");

        var dataList = data.ToList();
        sw = Stopwatch.StartNew();
        for (int i = 0; i < Iterations; i++)
        {
            double sum = 0;
            for (int j = 0; j < dataList.Count; j++)
            {
                sum += data[j];
            }
            if (Math.Abs(sum - correctSum) > 0.1)
            {
                Console.WriteLine("Summation failed");
                return;
            }
        }
        sw.Stop();
        Console.WriteLine("For loop with List: {0}", sw.ElapsedMilliseconds);

        sw = Stopwatch.StartNew();
        for (int i = 0; i < Iterations; i++)
        {
            double sum = 0;
            foreach (double d in dataList)
            {
                sum += d;
            }
            if (Math.Abs(sum - correctSum) > 0.1)
            {
                Console.WriteLine("Summation failed");
                return;
            }
        }
        sw.Stop();
        Console.WriteLine("Foreach loop with List: {0}", sw.ElapsedMilliseconds);
    }

3
Ini adalah tes yang sangat buruk. a) Anda melakukan iterasi yang terlalu sedikit untuk mendapatkan jawaban konklusif b) Utas itu. Tidur tidak akan benar-benar menunggu satu milidetik. Gunakan metode yang sama seperti yang dilakukan Jon Skeet dalam jawabannya.
jgauffin

1
99,99% dari waktu pasti dihabiskan di utas. Tidur (yang tidak menjamin seberapa cepat ia akan kembali kecuali tidak sebelum setidaknya saat itu). Perulangan sangat cepat dan tidur sangat lambat, Anda tidak menggunakannya nanti untuk menguji yang pertama.
Ronan Thibaudau

3

Anda benar-benar dapat mengacaukan kepalanya dan melakukan IQueryable. Penutupan sebaliknya:

myList.ForEach(c => Console.WriteLine(c.ToString());

3
Saya akan mengganti baris kode Anda dengan myList.ForEach(Console.WriteLine).
Mehrdad Afshari

2

Saya tidak akan mengharapkan siapa pun untuk menemukan perbedaan kinerja "besar" antara keduanya.

Saya kira jawabannya tergantung pada apakah kumpulan yang Anda coba akses memiliki implementasi akses pengindeks yang lebih cepat atau implementasi akses IEnumerator yang lebih cepat. Karena IEnumerator sering menggunakan pengindeks dan hanya memegang salinan posisi indeks saat ini, saya berharap akses enumerator setidaknya sama lambat atau lebih lambat dari akses indeks langsung, tetapi tidak banyak.

Tentu saja jawaban ini tidak memperhitungkan optimisasi apa pun yang mungkin diterapkan oleh kompiler.


C # compiler melakukan sedikit optimasi, itu benar-benar meninggalkannya ke JITter.
ljs

Nah, JITter adalah kompiler ... Benar?
JohannesH

2

Perlu diingat bahwa for-loop dan foreach-loop tidak selalu setara. Daftar enumerator akan mengeluarkan pengecualian jika daftar berubah, tetapi Anda tidak akan selalu mendapatkan peringatan itu dengan loop normal. Anda bahkan mungkin mendapatkan pengecualian berbeda jika daftar berubah pada waktu yang salah.


Jika daftar berubah dari bawah Anda maka Anda tidak dapat mengandalkan enumerator yang mendukung loop foreach untuk memberi tahu Anda itu. Ini tidak akan memeriksa lagi setelah mengembalikan nilai kepada Anda, menghasilkan balapan.
hoodaticus
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.