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


123

私はメッシュレンダリングマネージャーを作成していて、同じシェーダーを使用するすべてのメッシュをグループ化してから、そのシェーダーパスでこれらをレンダリングすることをお勧めします。

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



1
@MarcGravellの回答を承認済みのものに設定することを検討してください。たとえば、linqからsqlへの状況があり、linqがfor / foreachよりも高速です。
paqogomez 2014年

回答:


221

なぜLINQの方が速いのですか?また、内部でループを使用します。

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


7
あなたの経験では、LINQはより高速であり、コードの読み取りと維持が難しくなっていますか?説明してください。
codymanix 2011年

87
後ろ向きだったと思います。彼はLINQは遅いと言っています。これは頭​​上が原因です。彼はまた、LINQの方が読みやすく、保守しやすいと述べています。
ジョセフ・マッキンタイア

5
ごめんなさい。その間、linqとforまたはforeachのパフォーマンスを比較することはたくさんありましたが、ほとんどの場合、linqの方が高速でした。
Offler 2013年

34
正直なところ、foreachループはLINQメソッドよりも読みやすくなっています。私はLINQを使っています。それはクールだからです:)
LuckyLikey

4
はい。ただし、場合によっては、LINQによって読みやすさが向上する可能性があります。そのため、私の心のないコメント<3を忘れてください
LuckyLikey

59

LINQ-to-Objectsは一般に、いくつかの限界的なオーバーヘッド(複数の反復子など)を追加します。それはまだループを行う必要があり、およびデリゲート呼び出すを持ち、かつ一般的に、これは事実上検出できないだろうほとんどのコードで撮影した変数などで取得するためのいくつかの余分な間接参照を行う必要があります、そしてより多くのコードを理解するために単純で与えられます。

LINQ-to-SQLのような他のLINQプロバイダーでは、クエリはサーバーでフィルタリングできるため、フラットよりもはるかに優れているはずですがとにかくforeachブランケットを実行しなかった可能性が高いので、必ずしも公平ではありません。比較。"select * from foo"

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


別の回答では、メモリ内コレクションでLINQを使用しないことをほのめかしました-例List<Foo>; 代わりに、foreachこれらのコレクションでブロックを使用する必要があります。foreachこれらのコンテキストで使用することをお勧めします。私の懸念:パフォーマンスの問題を検出したforeach 場合にのみ、LINQクエリを置き換える必要がありますか?今後は、foreach最初のものを検討します。
IAbstract


15

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

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


3
「Microsoftが実装できる」という行は好きですが、フレームワークをアップグレードしなくても可能ですか?
Shrivallabh 2015年

1
LINQは、最終的にネイティブ実装に変換されるため、ネイティブ実装よりも実際に速くなることはありません。より高速なLINQマシンコードを変換するために使用できる特別なLINQ CPU命令とLINQレジスタはありません。ある場合、それらは非LINQコードでも使用されます。
mg30rg 2017年

確かに、ある時点で特定のリンク操作がマルチスレッド化されたり、ある時点でGPUを利用したりすることもあります。
ジョン株式



5

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

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

}

これは私が得たものです:Exists = True Time = 274 Exists = True Time = 314
PmanAce

2
最初にlinqを実行し、後でforeachを実行することを検討した場合、それもいくつかの違いをもたらす可能性があります
Muhammad Mamoor Khan

3
面白い。私が得たExists=True Time=184 Exists=True Time=135ことは、Apacheゲーミングノートパソコン(10勝、C#7.3)にあります。コンパイルされ、デバッグモードで実行されました。私がテストを逆にすると私は得るExists=True Time=158 Exists=True Time=194。Linqはより最適化されているようです。
James Wilkins、

1
この記事には、オブジェクトテストに関する誤解があります。List.Existsと.Containsがforeachよりもパフォーマンスが良いように見えるのは間違いなく興味深いことです。.Existsはエンティティへのlinqメソッドではなく、リストでのみ機能することに注意することが重要です。linqと同等のメソッドである.Any()は、foreachよりも確実に遅くなります。
AbdulG

3

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

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

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

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

    • 注:ベンチマークの際は、覚えておいてください。2つの連続するテストで同じ配列/リストを使用すると、CPUキャッシュによって2番目のテストが高速になります。*
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.