402

C#/VB.NET/.NET では、どちらのループが速く実行されますforforeach?

ずっと前に、ループはループforよりも高速に動作することを読んで以来、すべてのコレクション、ジェネリック コレクション、すべての配列などに当てはまると思い込んでいました。foreach

私は Google を精査し、いくつかの記事を見つけましたが、それらのほとんどは決定的ではなく (記事のコメントを読んでください)、自由回答です。

理想的なのは、各シナリオをリストし、それに対する最適なソリューションを用意することです。

例(それがどうあるべきかの単なる例):

  1. 1000以上の文字列の配列を反復するため -forよりも優れていますforeach
  2. IList(非ジェネリック)文字列を反復処理するため-foreachよりも優れていますfor

同じことについてウェブ上で見つかったいくつかの参照:

  1. エマニュエル・シャンツァーによるオリジナルの壮大な古い記事
  2. CodeProject FOREACH 対。為に
  3. ブログ - するforeachかしないかforeach、それが問題です
  4. ASP.NET フォーラム - NET 1.1 C# forvsforeach

[編集]

読みやすさの側面とは別に、私は事実と数字に本当に興味があります。絞り込まれたパフォーマンス最適化のラスト マイルが問題になるアプリケーションがあります。

4

41 に答える 41

418

Patrick Smacchiaは先月、これについて次のような結論をブログに書きました。

  • List の for ループは、List の foreach ループよりも 2 倍以上安くなります。
  • 配列のループは、リストのループよりも約 2 倍安くなります。
  • 結果として、for を使用して配列をループする方が、foreach を使用してリストをループするよりも 5 倍安くなります (これは私たち全員が行っていることだと思います)。
于 2008-12-13T20:14:50.377 に答える
177

まず、Dmitry の (現在は削除された) answer に対する反訴です。配列の場合、C# コンパイラはforeach、同等のforループの場合とほぼ同じコードを出力します。これが、このベンチマークの結果が基本的に同じである理由を説明しています。

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);
    }
}

結果:

For loop: 16638
Foreach loop: 16529

次に、コレクション型が重要であるという Greg の指摘の検証 -List<double>上記で配列を a に変更すると、根本的に異なる結果が得られます。一般的に大幅に遅くなるだけでなく、 foreach はインデックスによるアクセスよりも大幅に遅くなります。そうは言っても、私はほとんどの場合、コードを単純にする for ループよりも foreach を好みます。

于 2009-01-23T08:26:50.420 に答える
164

foreachforループは、ループよりも具体的な意図を示します。

ループを使用するforeachと、コレクション内の場所に関係なく、コレクションの各メンバーに対して何かを行うことを計画していることを、コードを使用するすべての人に示します。また、元のコレクションを変更していないことも示しています (変更しようとすると例外がスローされます)。

のもう 1 つの利点は、各要素が実際にインデックスを持っている でのみ意味をforeach持つ任意IEnumerableの で機能することです。forIList

ただし、要素のインデックスを使用する必要がある場合は、もちろんforループの使用を許可する必要があります。ただし、インデックスを使用する必要がない場合、インデックスを使用するとコードが乱雑になります。

私の知る限り、パフォーマンスに重大な影響はありません。将来のある段階で、コードをforeach複数のコアで実行するように適応させることがより簡単になるかもしれませんが、現時点では心配する必要はありません。

于 2009-12-22T15:08:09.773 に答える
53

パフォーマンスに関する議論がある場合はいつでも、定量的な結果を使用してケースをサポートできるように、小さなテストを作成するだけで済みます。

StopWatch クラスを使用して、正確にするために何かを数百万回繰り返します。(これは for ループがないと難しいかもしれません):

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

この結果に指を交差させたところ、違いはごくわずかであり、コードが最も保守しやすいものであれば何でも実行した方がよいでしょう。

于 2009-12-22T15:08:32.550 に答える
52

それは常に近いでしょう。配列の場合 for、 の方がわずかに速い場合もforeachありますが、より表現力があり、LINQ などを提供します。一般的には、foreach.

さらに、foreach一部のシナリオでは最適化される場合があります。たとえば、リンクされたリストは、インデクサーではひどいかもしれませんが、foreach. 実際、標準LinkedList<T>ではこの理由からインデクサーさえ提供していません。

于 2008-12-13T19:56:21.600 に答える
37

私の推測では、おそらく 99% のケースでは重要ではないでしょう。では、最も適切な方法ではなく、より高速な方法を選択する理由は何ですか?

于 2008-12-13T19:51:41.017 に答える
33

ループよりもループを好む のには、十分な理由があります。ループを使用できる場合、上司は正しいです。foreachforforeach

ただし、すべての反復が単純にリストを 1 つずつ順に処理するわけではありません。彼が禁止している場合、はい、それは間違っています。

私があなただったら、あなたの自然な for ループをすべて recursion に変えます。それは彼に教えるだろうし、それはあなたにとっても良い精神練習になる.

于 2009-12-22T15:13:35.243 に答える
32

この 2 つの間に大きなパフォーマンスの違いがあるとは考えにくいです。いつものように、「どちらが速いか」という問題に直面したとき。「これなら測定できる」と常に考えてください。

ループ本体に同じことを行う 2 つのループを記述し、両方を実行して時間を計測し、速度の違いを確認します。これは、ほとんど空の本体と、実際に行うことと同様のループ本体の両方で行います。コレクションの種類が異なればパフォーマンス特性も異なる可能性があるため、使用しているコレクションの種類でも試してみてください。

于 2009-01-23T07:36:03.830 に答える
18

TechEd 2005 の Jeffrey Richter:

「私は何年にもわたって、C# コンパイラが基本的に私にとってうそつきであることを学びました。」..「それは多くのことについて嘘をついています。」..「foreach ループを実行するときのように...」 ..「...それは、ユーザーが作成する 1 行の小さなコードですが、それを行うために C# コンパイラが吐き出すものは驚異的です。そこに try/finally ブロックがあり、finally ブロック内で変数が IDisposable インターフェイスにキャストされ、キャストが成功した場合は Dispose メソッドが呼び出され、ループ内で Current プロパティと MoveNext メソッドがループ内で繰り返し呼び出されます。オブジェクトはカバーの下で作成されています. 多くの人が foreach を使用しています. なぜならコーディングが非常に簡単で実行も簡単だからです.." .. "foreach はパフォーマンスの点であまり良くありません.

オンデマンド Web キャスト: http://msevents.microsoft.com/CUI/WebCastEventDetails.aspx?EventID=1032292286&EventCategory=3&culture=en-US&CountryCode=US

于 2009-12-03T15:38:08.113 に答える
12

ばかげてる。for ループを禁止するやむを得ない理由はありません。

パフォーマンスのベンチマークとその他の議論については、Jon Skeet のブログを参照してください。

于 2009-12-22T15:11:28.707 に答える
11

オブジェクトのコレクションを操作する場合は のforeach方が優れていますが、数値をインクリメントする場合はforループの方が優れています。

最後のケースでは、次のようなことができることに注意してください。

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

しかし、確かにパフォーマンスが向上するわけではなく、実際には に比べてパフォーマンスが低下しforます。

于 2009-12-22T15:08:14.127 に答える
10

これはあなたを救うはずです:

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

使用する:

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

より大きな勝利のために、あなたはパラメータとして3人の代表をとることができます。

于 2009-12-22T18:37:42.397 に答える
9

これには、ほとんどの「どちらが速いか」という質問と同じ 2 つの答えがあります。

1) 測らないと分からない。

2) (だって…) 場合による。

これは、反復処理する IEnumerable の型 (または複数の型) に対して、「this[int index]」メソッドのコストと比較して、「MoveNext()」メソッドのコストに依存します。

「foreach」キーワードは、一連の操作の省略形です。IEnumerable で GetEnumerator() を 1 回呼び出し、反復ごとに MoveNext() を 1 回呼び出し、型チェックを行います。パフォーマンス測定に影響を与える可能性が最も高いのは、O(N) 回呼び出されるため、MoveNext() のコストです。安いかもしれませんが、そうではないかもしれません。

"for" キーワードの方が予測しやすいように見えますが、ほとんどの "for" ループ内には "collection[index]" のようなものがあります。これは単純な配列のインデックス操作のように見えますが、実際にはメソッド呼び出しであり、そのコストは、反復するコレクションの性質に完全に依存します。おそらく安いですが、そうではないかもしれません。

コレクションの基になる構造が本質的にリンクされたリストである場合、MoveNext は非常に安価ですが、インデクサーのコストは O(N) になる可能性があり、"for" ループの実際のコストは O(N*N) になります。

于 2014-11-13T06:22:22.247 に答える
9

for- ループと- ループの速度の違いは、foreach配列、リストなどの一般的な構造をループしている場合はLINQわずかであり、コレクションに対してクエリを実行すると、ほとんどの場合わずかに遅くなりますが、書く方が優れています! 他のポスターが言ったように、ミリ秒の余分なパフォーマンスではなく、表現力を求めてください.

これまでに述べられていないことは、foreachループがコンパイルされると、ループが繰り返し処理されるコレクションに基づいてコンパイラーによって最適化されるということです。つまり、使用するループがわからない場合は、ループを使用する必要がありますforeach。コンパイル時に最適なループが生成されます。それもより読みやすいです。

ループのもう 1 つの重要な利点は、コレクションの実装が (たとえばforeachintarrayから aに) 変更された場合、ループでコードを変更する必要がないことです。List<int>foreach

foreach (int i in myCollection)

上記は、コレクションのタイプに関係なく同じですが、ループでは、からに変更したfor場合、次はビルドされません。myCollectionarrayList

for (int i = 0; i < myCollection.Length, i++)
于 2008-12-13T20:38:14.760 に答える
8

「for ループの使用が許容されることを彼に納得させるために使用できる引数はありますか?」

いいえ、あなたの上司が、どのプログラミング言語構造を使用するかを指示するレベルまで細かく管理している場合、あなたが言えることは何もありません。ごめん。

于 2009-12-22T15:50:52.980 に答える
7

すべての言語構造には、使用に適した時期と場所があります。C# 言語に 4 つの個別の反復ステートメントがあるのには理由があります。それぞれが特定の目的のために存在し、適切な用途があります。

for上司と話し合って、ループに目的がある理由を合理的に説明することをお勧めします。反復よりもfor反復ブロックの方がアルゴリズムをより明確に説明する場合がありforeachます。これが当てはまる場合、それらを使用するのが適切です。

私はあなたの上司にも指摘したいと思います.パフォーマンスは問題ではなく、実用的な方法であるべきではありません-それは、アルゴリズムを簡潔で意味のある、保守可能な方法で表現することの問題です。このようなマイクロ最適化は、パフォーマンスの最適化のポイントを完全に見逃しています。実際のパフォーマンスの利点は、ループの再構築ではなく、アルゴリズムの再設計とリファクタリングから得られるからです。

合理的な議論の後でもこの権威主義的な見解が残っている場合、どのように進めるかはあなた次第です. 個人的には、合理的思考が妨げられるような環境で働くことには満足できず、別の雇用主の下で別のポジションに移動することを検討します. ただし、動揺する前に話し合うことを強くお勧めします。単純な誤解があるだけかもしれません。

于 2009-12-22T18:11:14.850 に答える
7

おそらく、列挙しているコレクションのタイプとそのインデクサーの実装によって異なります。ただし、一般的には、 を使用foreachする方がより良いアプローチである可能性があります。

また、IEnumerableインデクサーだけでなく、あらゆるもので動作します。

于 2009-01-23T07:35:12.617 に答える
6

本当にfor速いかどうかは別として。foreachどちらかを選択することがパフォーマンスに大きな影響を与えるとは思えません。

アプリケーションを最適化する最善の方法は、実際のコードのプロファイルを作成することです。これにより、最も多くの作業/時間を占めるメソッドが特定されます。最初にそれらを最適化します。それでもパフォーマンスが許容できない場合は、手順を繰り返します。

原則として、マイクロ最適化はあまり効果が得られないため、避けることをお勧めします。唯一の例外は、特定されたホット パスを最適化する場合です (つまり、プロファイリングで使用頻度の高いいくつかのメソッドが特定された場合、これらを広範囲に最適化することが理にかなっている場合があります)。

于 2009-12-22T15:31:32.273 に答える
4

この 2 つは、ほぼ同じように実行されます。両方を使用するコードを書いてから、彼に IL を見せてください。同等の計算を表示する必要があります。つまり、パフォーマンスに違いはありません。

于 2009-12-22T15:08:28.747 に答える
4

for ループのようなものの使用を完全に禁止するのは少し奇妙に思えます。

ここには、2 つのループのパフォーマンスの違いの多くをカバーしている興味深い記事があります。

個人的には foreach の方が for ループよりも読みやすいと思いますが、目の前の仕事に最適なものを使用する必要があり、for ループの方が適切な場合は、foreach ループを含めるために余分な長いコードを記述する必要はありません。

于 2009-12-22T15:12:25.010 に答える
4

ほとんどの場合、実際には違いはありません。

通常、明示的な数値インデックスがない場合は常に foreach を使用する必要があり、実際に反復可能なコレクションがない場合は常に for を使用する必要があります (たとえば、上の三角形の 2 次元配列グリッドを反復処理する場合)。 . 選択できるケースもあります。

マジック ナンバーがコードに現れ始めると、for ループを維持するのが少し難しくなる可能性があると主張する人もいるかもしれません。for ループが禁止されているという理由だけで、for ループを使用できず、代わりにコレクションを構築するか、ラムダを使用してサブコレクションを構築する必要があることに腹を立てるのは正しいことです。

于 2009-12-22T15:12:51.997 に答える
4

あなたは本当に彼の頭を台無しにして、代わりに IQueryable .foreach クロージャーに行くことができます:

myList.ForEach(c => Console.WriteLine(c.ToString());
于 2009-12-22T15:45:01.477 に答える
3

少し前にテストしたところ、forループはループよりもはるかに高速であることがforeachわかりました。原因は簡単です。foreachループは最初IEnumeratorにコレクションの をインスタンス化する必要があります。

于 2008-12-13T19:57:33.780 に答える
3

for はより単純なロジックを実装しているため、foreach よりも高速です。

于 2008-12-13T19:59:32.233 に答える
3

Jeffrey Richter は、最近のポッドキャストで for と foreach のパフォーマンスの違いについて話しました: http://pixel8.infragistics.com/shows/everything.aspx#Episode:9317

于 2009-01-23T10:16:38.500 に答える
2

for-loop と foreach-loop は常に同等ではないことに注意してください。リスト列挙子は、リストが変更された場合に例外をスローしますが、通常の for ループで常にその警告を受け取るとは限りません。リストが間違ったタイミングで変更された場合、別の例外が発生することさえあります。

于 2009-02-17T16:59:48.163 に答える
2

この 2 つのパフォーマンスに「大きな」違いがあるとは誰も思いません。

答えは、アクセスしようとしているコレクションのインデクサー アクセスの実装が高速か、IEnumerator アクセスの実装が高速かによって異なると思います。IEnumerator はしばしばインデクサーを使用し、現在のインデックス位置のコピーを保持するだけなので、列挙子へのアクセスは、直接のインデックス アクセスと少なくとも同じか、それよりも遅くなると予想されますが、それほどではありません。

もちろん、この答えは、コンパイラが実装する可能性のある最適化を考慮していません。

于 2009-01-23T10:17:18.403 に答える
1

「Writing High-Performance .NET Code」の著者である Ben Watson は次のように述べています。

「これらの最適化はあなたのプログラムにとって重要ですか? あなたのプログラムが CPU バウンドであり、コレクションの反復が処理のコア部分である場合にのみ.そもそもそれがプログラムの重要な部分であったかどうかだけが重要です。私の哲学は次のとおりです。ほとんどの人はこれを知る必要はありませんが、知っている場合は、システムのすべての層を理解することが重要であり、賢明な選択を行うことができます。」 .

最も詳しい説明は、http: //www.codeproject.com/Articles/844781/Digging-Into-NET-Loop-Performance-Bounds-checkingにあります。

于 2015-11-08T20:37:48.030 に答える
1

Windows Mobile での私のプロジェクトでforは、コントロール コレクションにループを使用しました。20 個のコントロールに 100 ミリ秒かかりました。foreachループは 4 ミリ秒しか使用しませんでした。それはパフォーマンスの問題でした...

于 2011-08-10T00:19:56.513 に答える
1

for と foreach の収集速度に基づいて、この詳細について説明しました。

List -For ループは Foreach ループよりもわずかに高速です

ArrayList - For ループは、Foreach ループよりも約 2 倍以上高速です。

配列 - どちらも同じ速度ですが、Foreach ループの方が少し速いようです。

于 2016-01-11T04:46:32.080 に答える
1

ほとんどの場合、 for は foreach よりわずかに速いと思いますが、これは本当に要点を逃しています。私が言及していないことの 1 つは、あなたが話しているシナリオ (つまり、大量の Web アプリ) では、for と foreach のパフォーマンスの違いがサイトのパフォーマンスに影響しないということです。v. foreach ではなく、リクエスト/レスポンス時間と DB 時間によって制限されます。

とはいえ、foreach に対するあなたの嫌悪感は理解できません。私の意見では、 foreach は通常、どちらかを使用できる状況でより明確です。私は通常、醜い非標準的な方法でコレクションをトラバースする必要がある状況のために予約します。

于 2009-12-22T15:58:18.600 に答える
0

3 つのネストされたループ (on List<MyCustomType>) を使用して、大きなデータの解析を行う必要がありました。上記の Rob Fonseca-Ensor の投稿を使用して、 forforeachを使用して時間を比較し、違いを比較すると面白いと思いました。

違いは次のとおりです: foreach (foreach{foreach{forech{}}} のようにネストされた 3 つの foreach は171.441秒でジョブを実行しましたが、for (for{for{for{}}}) は158.616秒でジョブを実行しました。

13 秒というのは、これを行うための時間が約13%短縮されたということです。これは私にとってはかなり重要なことです。ただし、foreach は、3 つのインデックス付き for を使用するよりもはるかに読みやすいことは間違いありません...

于 2014-06-27T15:04:55.190 に答える
0

少なくとも、同僚や上層部がそう言っているのを見たことがありませforforeach。彼がすべての場合にそれを使用するように求めている場合も同じことが当てはまります!

于 2009-12-22T15:11:53.467 に答える