15

foreachvsを使用した場合のパフォーマンスをテストするために、次のように記述しましたLINQ

private class Widget
{
    public string Name { get; set; }
}

static void Main(string[] args)
{
    List<Widget> widgets = new List<Widget>();
    int found = 0;

    for (int i = 0; i <= 500000 - 1; i++)
        widgets.Add(new Widget() { Name = Guid.NewGuid().ToString() });

    DateTime starttime = DateTime.Now;

    foreach (Widget w in widgets)
    {
        if (w.Name.StartsWith("4"))
            found += 1;
    }

    Console.WriteLine(found + " - " + DateTime.Now.Subtract(starttime).Milliseconds + " ms");

    starttime = DateTime.Now;
    found = widgets.Where(a => a.Name.StartsWith("4")).Count();

    Console.WriteLine(found + " - " + DateTime.Now.Subtract(starttime).Milliseconds + " ms");

    Console.ReadLine();
}

次のような出力が得られます。

31160 - 116ms
31160 - 95 ミリ秒

すべての実行で、LINQ は foreach よりも約 20% 優れています。LINQ 拡張メソッドが標準の c# を内部で使用していることは、私の理解でした。

では、この場合、なぜ LINQ の方が速いのでしょうか?

編集:

そのため、日時の代わりにストップウォッチを使用するようにコードを変更しても、同じ結果が得られます。最初に LINQ クエリを実行すると、結果は LINQ が foreach よりも約 20% 遅いことを示しています。これは、ある種の JIT ウォームナップの問題である必要があります。私の質問は、テスト ケースで JIT ウォームアップをどのように補正するかです。

4

2 に答える 2

15

ウォーミングアップをしていないからです。ケースを逆にすると、正反対の結果が得られます。

31272 - 110ms
31272 - 80 ms

ウォームアップの追加を開始し、ストップウォッチを使用してタイミングを改善します。

ウォームアップでテストを実行する:

        //WARM UP:
        widgets.Where(a => a.Name.StartsWith("4")).Count();

        foreach (Widget w in widgets)
        {
            if (w.Name.StartsWith("4"))
                found += 1;
        }

        //RUN Test
        Stopwatch stopwatch1 = new Stopwatch();
        stopwatch1.Start();

        found = widgets.Where(a => a.Name.StartsWith("4")).Count();
        stopwatch1.Stop();

        Console.WriteLine(found + " - " + stopwatch1.Elapsed);

        found = 0;
        Stopwatch stopwatch2 = new Stopwatch();
        stopwatch2.Start();

        foreach (Widget w in widgets)
        {
            if (w.Name.StartsWith("4"))
                found += 1;
        }
        stopwatch2.Stop();

        Console.WriteLine(found + " - " + stopwatch2.Elapsed);

結果:

31039 - 00:00:00.0783508
31039 - 00:00:00.0766299
于 2013-06-17T13:10:36.597 に答える
2

以下を比較して、しばらく前にプロファイリングを行いました。

  • 正規表現を使用する/使用しないオブジェクトへの LINQ

  • 正規表現を使用する/使用しないラムダ式

  • 正規表現を使用する/使用しない従来の反復

私が見つけたのは、LINQ、Lambda、および従来の反復は常にほぼ同じでしたが、実際のタイミングの違いは正規表現式にあったということです。正規表現を追加するだけで、評価が遅くなりました(かなり遅くなりました)。(詳細はこちら: http://www.midniteblog.com/?p=72 )

上に表示されているのは、おそらく同じコード ブロックで両方のテストを実行しているためです。1 つをコメント アウトし、タイミングを合わせてから、もう 1 つをコメント アウトしてみてください。また、デバッガーではなく、リリース ビルドを実行していることを確認してください。

于 2013-06-17T13:03:55.393 に答える