2014-04-04 394 views
8

有人可以解釋這些結果嗎? 我知道有重複的問題,但我還沒有發現,也得出了同樣的結論作爲我的結果一個問題:○LINQ vs foreach vs性能測試結果

using System; 
using System.Collections.Generic; 
using System.Diagnostics; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks; 

namespace SpeedTest 
{ 
    class Person 
    {  
     public Person(string name) 
     { 
      this.Name = name; 
     } 

     public string Name { get; set; } 
    } 

    class Program 
    { 
     static void Main(string[] args) 
     { 
      var people = new List<Person>(); 
      AddTwins("FRANCISCO", people); 
      var stopwatch = new Stopwatch(); 

      string name = "OCSICNARF"; 

      long linqTime = 0L; 
      long foreachTime = 0L; 
      long forTime = 0L; 

      stopwatch.Start(); 
      Person person0; 
      var result = from person in people 
         where person.Name == name 
         select person; 
      person0 = result.First(); 
      linqTime = stopwatch.ElapsedMilliseconds; 
      stopwatch.Restart(); 
      Person person1; 
      foreach (Person p in people) 
      { 
       if (p.Name == name) 
       { 
        person1 = p; 
        break; 
       } 
      } 
      foreachTime = stopwatch.ElapsedMilliseconds; 
      stopwatch.Restart(); 
      Person person2; 
      for (int i = 0; i < people.Count; i++) 
      { 
       if (people[i].Name == name) 
       { 
        person2 = people[i]; 
        break; 
       } 
      } 
      forTime = stopwatch.ElapsedMilliseconds; 
      stopwatch.Stop(); 

      Console.WriteLine(string.Format("LINQ took {0}ms", linqTime)); 
      Console.WriteLine(string.Format("FOREACH took {0}ms", foreachTime)); 
      Console.WriteLine(string.Format("FOR took {0}ms", forTime)); 
     } 

     static void AddTwins(string name, List<Person> people) 
     { 
      AddTwins(people, name, ""); 
     } 

     private static void AddTwins(List<Person> people, string choices, string chosen) 
     { 
      if (choices.Length == 0) 
      { 
       people.Add(new Person(chosen)); 
      } 
      else 
      { 
       for (int i = 0; i < choices.Length; i++) 
       { 
        // choose 
        char c = choices[i]; 
        string choose1 = choices.Substring(0, i); 
        string choose2 = choices.Substring(i + 1); 
        choices = choose1 + choose2; 

        // explore 
        AddTwins(people, choices, chosen + c); 

        // Unchoose 
        string unchoose1 = choices.Substring(0, i); 
        string unchoose2 = choices.Substring(i); 
        choices = unchoose1 + c + unchoose2; 
       } 
      } 
     } 
    } 
} 

enter image description here

+0

請參閱http://ericlippert.com/2013/05/14/benchmarking-mistakes-part-one/ –

回答

16

你永遠不執行LINQ查詢,你只需要創建它。您應該使用ToListToArray方法來強制迭代,可能您不會得到不同的結果,因爲LINQ也使用foreach循環。

編輯LINQ需要多一點時間,因爲您正在迭代所有項目。但是在你的另外兩個循環中,只要你找到一個匹配,你就會打破循環。嘗試使用FirstOrDefault而不是Where,您應該得到相同(或類似)的結果。

people.FirstOrDefault(p => p.Name == name); 
+0

我的不好我剛纔意識到,看到新的結果/代碼。 –

1

的LINQ一個正在沒有時間,因爲查詢從未真正評估

Linq is lazy對於大多數操作,只有在某人開始枚舉結果時纔會真正做任何事情。

如果添加

result.Count(); // add this line, query will be evaluated 
linqTime = stopwatch.ElapsedMilliseconds; 
stopwatch.Restart(); 

的話,我敢肯定你有一個非零結果爲LINQ。

+0

是的,我注意到了,但你們對我來說太快了。看到新的結果。如果LINQ查詢應該像foreach循環一樣有一個foreach,爲什麼它更慢? –

+0

如果你看看它生成的代碼,foreach可能非常「平坦」,其中生成的代碼*可能*有一些額外的方法調用來進出foreach,併產生返回的東西和東西像那樣。 –

0

Sum顯然非常重要,Sum必須在堆上存儲列表枚舉器的裝箱實例,並使用該堆對象迭代列表。內聯的foreach和for循環都避免了這種情況;前者是因爲List的公共GetEnumerator方法返回值類型。如果存儲對IEnumerable<Person>變量中的人的引用,則foreach循環花費更長的時間才能獲得結果。

此外,linq必須爲where迭代器和委託傳遞給它的對象創建對象,並且它會執行更多的空檢查,以便在任何參數爲null時引發信息異常。這可以解釋linq代碼所需的額外時間。