簡體   English   中英

LINQ 語句是否比“foreach”循環更快?

[英]Is a LINQ statement faster than a 'foreach' loop?

我正在編寫一個網格渲染管理器,並認為將所有使用相同着色器的網格進行分組,然后在我在該着色器通道中渲染這些網格是個好主意。

我目前正在使用foreach循環,但想知道使用 LINQ 是否可以提高性能?

為什么 LINQ 應該更快? 它還在內部使用循環。

大多數情況下,LINQ 會慢一點,因為它引入了開銷。 如果您非常關心性能,請不要使用 LINQ。 使用 LINQ 是因為您想要更短、更易讀和可維護的代碼。

LINQ-to-Objects通常會增加一些邊際開銷(多個迭代器等)。 它仍然必須執行循環,具有委托調用,並且通常必須執行一些額外的解除引用以獲取捕獲的變量等。在大多數代碼中,這實際上是無法檢測到的,並且更易於理解的代碼所能提供的更多

使用其他 LINQ 提供程序(如 LINQ-to-SQL),那么由於查詢可以在服務器上進行過濾,它應該比平面foreach好得多,但是很可能無論如何您都不會進行全面的"select * from foo" ,所以這不一定是公平的比較。

重新 PLINQ; 並行性可能會減少經過的時間,但由於線程管理等的開銷,總 CPU 時間通常會增加一點。

我認為LINQ最好在foreach循環中使用,因為它可以使您的代碼更加簡潔明了。 但是LINQ比foreach慢。 要獲得更多信息,請閱讀文章LINQ vs FOREACH vs FOR Loop Performance

LINQ 現在變慢了,但在某些時候它可能會變得更快。 LINQ 的好處是你不必關心它是如何工作的。 如果想出一種新方法,而且速度非常快,Microsoft 的人員甚至可以在不告訴您的情況下實現它,並且您的代碼會快得多。

更重要的是,LINQ 更容易閱讀。 這應該是足夠的理由。

可能應該注意到for循環比foreach快。 因此,對於原始帖子,如果您擔心渲染器等關鍵組件的性能,請使用for循環。

參考: 在 .NET 中,哪個循環運行得更快,“for”還是“foreach”?

如果您對多核使用並行 LINQ,您可能會獲得性能提升。 請參閱並行 LINQ (PLINQ) (MSDN)。

我對這個問題很感興趣,所以我剛剛做了一個測試。 在 Intel(R) Core(TM) i3-2328M CPU @ 2.20GHz, 2200 Mhz, 2 Core(s) with 8GB ram 上使用 .NET Framework 4.5.2,運行 Microsoft Windows 7 Ultimate。

看起來 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

}

這實際上是一個相當復雜的問題。 Linq 使某些事情很容易做,如果你自己實現它們,你可能會絆倒(例如 linq .Except())。 這尤其適用於 PLinq,尤其適用於 PLinq 實現的並行聚合。

一般來說,對於相同的代碼,由於委托調用的開銷,linq 會更慢。

但是,如果您正在處理大量數據,並對元素應用相對簡單的計算,則在以下情況下您將獲得巨大的性能提升:

  1. 您使用數組來存儲數據。
  2. 您使用 for 循環來訪問每個元素(而不是 foreach 或 linq)。

    • 注意:在進行基准測試時,請大家記住——如果連續兩次測試使用相同的數組/列表,CPU 緩存會使第二次測試更快。 *

以上答案在2010年可能是正確的,... 15。 但我認為情況已不再如此:

當我運行此比較代碼時。 我得到以下結果:

    var time = Stopwatch.StartNew();
    var loops = 10000000;
    time.Start();
    var arr = new string[loops];
    for (var i = 0; i < loops; i++)
    {
        arr[i] = "Loop" + i;
    }
    time.Stop();
    Console.WriteLine("TIME: " + time.ElapsedMilliseconds + "ms");

我得到了以下結果

時間:6794ms

但是當我切換到linq時

    var time = Stopwatch.StartNew();
    var loops = 10000000;
    time.Start();
    var strList = Enumerable.Range(0, loops).Select(i => "Loop" + i).ToList();
    time.Stop();
    Console.WriteLine("TIME: " + time.ElapsedMilliseconds + "ms");

時間:2ms

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM