web-dev-qa-db-ja.com

LINQステートメントは「foreach」ループよりも高速ですか?

Mesh Rendering Managerを書いています。同じシェーダーを使用するすべてのメッシュをグループ化し、そのシェーダーパスにいる間にこれらをレンダリングするのは良い考えだと思いました。

現在foreachループを使用していますが、LINQを使用するとパフォーマンスが向上するかどうか疑問に思いました。

106
Neil Knight

なぜLINQを高速化する必要があるのですか?また、内部的にループを使用します。

ほとんどの場合、LINQはオーバーヘッドが発生するため、少し遅くなります。パフォーマンスを重視する場合は、LINQを使用しないでください。 LINQを使用するのは、読みやすく保守しやすい短いコードが必要なためです。

191
codymanix

LINQ-to-Objects 一般的には、いくつかのわずかなオーバーヘッド(複数の反復子など)を追加します。ループを実行する必要があります。andはデリゲートを呼び出します。andは一般に、キャプチャされた変数などを取得するために追加の逆参照を行う必要があります。検出不能、および以上単純なコードを理解することで提供されます。

LINQ-to-SQLのような他のLINQプロバイダーでは、クエリはサーバーでフィルター処理できるため、フラットforeachよりもはるかにbetterになりますが、ほとんどの場合は実行しなかったでしょう。ブランケット"select * from foo"とにかくなので、これは必ずしも公正な比較ではありません。

PLINQについて;並列処理によりelapsedの時間が短縮される場合がありますが、スレッド管理などのオーバーヘッドにより、通常は合計CPU時間は少し増加します。

56
Marc Gravell

LINQは、foreachループよりも優れていると思います。これは、コードがよりクリーンでわかりやすいためです。ただし、LINQはforeachよりも低速です。詳細については、記事LINQ vs FOREACH vs FORループパフォーマンスを参照してください。

18
Pranay Rana

LINQは現在は低速ですが、ある時点で高速になる可能性があります。 LINQの良い点は、どのように機能するかを気にする必要がないことです。信じられないほど高速な新しいメソッドが考え出された場合、Microsoftの人々はそれを実装することさえできますが、あなたのコードはもっと速くなります。

さらに重要なことは、LINQの方がはるかに読みやすいことです。それが十分な理由です。

14

forループはforeachよりも高速であることに注意してください。したがって、元の投稿では、レンダラーなどの重要なコンポーネントのパフォーマンスが心配な場合は、forループを使用します。

参照:。NETでは、どのループがより高速に実行されますか、 'for'または 'foreach'?

10
peewee_RotA

マルチコアにパラレルLINQを使用すると、パフォーマンスが向上する場合があります。 Parallel LINQ(PLINQ)(MSDN)を参照してください。

9
mcintyre321

これは実際には非常に複雑な質問です。 Linqを使用すると、特定のことが非常に簡単になります。自分で実装すると、つまずく可能性があります(例:linq .Except())。これは特にPLinqに適用され、特にPLinqによって実装される並列集約に適用されます。

一般に、同一のコードの場合、デリゲート呼び出しのオーバーヘッドのために、linqは遅くなります。

ただし、大量のデータを処理し、比較的単純な計算を要素に適用する場合、次の場合にパフォーマンスが大幅に向上します。

  1. 配列を使用してデータを保存します。
  2. Forループを使用して、各要素にアクセスします(foreachまたはlinqとは対照的)。

    • 注:ベンチマークを行うときは、覚えておいてください-2つの連続したテストに同じアレイ/リストを使用すると、CPUキャッシュにより2番目のテストが高速になります。 *
3
Adam Brown

私はこの質問に興味があったので、たった今テストをしました。 Microsoft Windows 7 Ultimateを実行している8GB RAMを搭載したIntel(R)Core(TM)i3-2328M CPU @ 2.20GHz、2200 Mhz、2コアでの.NET Framework 4.5.2の使用。

LINQは各ループの場合よりも高速であるように見えます。私が得た結果は次のとおりです。

Exists = True
Time   = 174
Exists = True
Time   = 149

このコードをコンソールアプリにコピーして貼り付け、テストすることもできたら面白いでしょう。オブジェクト(従業員)でテストする前に、整数で同じテストを試みました。 LINQも高速でした。

public class Program
{
    public class Employee
    {
        public int id;
        public string name;
        public string lastname;
        public DateTime dateOfBirth;

        public Employee(int id,string name,string lastname,DateTime dateOfBirth)
        {
            this.id = id;
            this.name = name;
            this.lastname = lastname;
            this.dateOfBirth = dateOfBirth;

        }
    }

    public static void Main() => StartObjTest();

    #region object test

    public static void StartObjTest()
    {
        List<Employee> items = new List<Employee>();

        for (int i = 0; i < 10000000; i++)
        {
            items.Add(new Employee(i,"name" + i,"lastname" + i,DateTime.Today));
        }

        Test3(items, items.Count-100);
        Test4(items, items.Count - 100);

        Console.Read();
    }


    public static void Test3(List<Employee> items, int idToCheck)
    {

        Stopwatch s = new Stopwatch();
        s.Start();

        bool exists = false;
        foreach (var item in items)
        {
            if (item.id == idToCheck)
            {
                exists = true;
                break;
            }
        }

        Console.WriteLine("Exists=" + exists);
        Console.WriteLine("Time=" + s.ElapsedMilliseconds);

    }

    public static void Test4(List<Employee> items, int idToCheck)
    {

        Stopwatch s = new Stopwatch();
        s.Start();

        bool exists = items.Exists(e => e.id == idToCheck);

        Console.WriteLine("Exists=" + exists);
        Console.WriteLine("Time=" + s.ElapsedMilliseconds);

    }

    #endregion


    #region int test
    public static void StartIntTest()
    {
        List<int> items = new List<int>();

        for (int i = 0; i < 10000000; i++)
        {
            items.Add(i);
        }

        Test1(items, -100);
        Test2(items, -100);

        Console.Read();
    }

    public static void Test1(List<int> items,int itemToCheck)
    {

        Stopwatch s = new Stopwatch();
        s.Start();

        bool exists = false;
        foreach (var item in items)
        {
            if (item == itemToCheck)
            {
                exists = true;
                break;
            }
        }

        Console.WriteLine("Exists=" + exists);
        Console.WriteLine("Time=" + s.ElapsedMilliseconds);

    }

    public static void Test2(List<int> items, int itemToCheck)
    {

        Stopwatch s = new Stopwatch();
        s.Start();

        bool exists = items.Contains(itemToCheck);

        Console.WriteLine("Exists=" + exists);
        Console.WriteLine("Time=" + s.ElapsedMilliseconds);

    }

    #endregion

}
2
Theo Kand.