2013-03-04 31 views
13

我對一個算法進行了一些優化,該算法在給定的數組中找到了大於X的最小數字,但後來我偶然發現了一個奇怪的差異。在下面的代碼中,「ForeachUpper」在625ms結束,「ForUpper」結束,我相信,幾個小時(瘋狂地慢)。爲什麼這樣?C# - 對於VS Foreach - 巨大的性能差異

class Teste 
{ 
    public double Valor { get; set; } 

    public Teste(double d) 
    { 
     Valor = d; 
    } 

    public override string ToString() 
    { 
     return "Teste: " + Valor; 
    } 
} 

    private static IEnumerable<Teste> GetTeste(double total) 
    { 
     for (int i = 1; i <= total; i++) 
     { 
      yield return new Teste(i); 
     } 
    } 
    static void Main(string[] args) 
    { 
     int total = 1000 * 1000*30 ; 
     double test = total/2+.7; 

     var ieTeste = GetTeste(total).ToList(); 


     Console.WriteLine("------------"); 

     ForeachUpper(ieTeste.Select(d=>d.Valor), test); 
     Console.WriteLine("------------"); 
     ForUpper(ieTeste.Select(d => d.Valor), test); 
     Console.Read(); 
    } 

    private static void ForUpper(IEnumerable<double> bigList, double find) 
    { 
     var start1 = DateTime.Now; 

     double uppper = 0; 
     for (int i = 0; i < bigList.Count(); i++) 
     { 
      var toMatch = bigList.ElementAt(i); 
      if (toMatch >= find) 
      { 
       uppper = toMatch; 
       break; 
      } 
     } 

     var end1 = (DateTime.Now - start1).TotalMilliseconds; 

     Console.WriteLine(end1 + " = " + uppper); 
    } 

    private static void ForeachUpper(IEnumerable<double> bigList, double find) 
    { 
     var start1 = DateTime.Now; 

     double upper = 0; 
     foreach (var toMatch in bigList) 
     { 
      if (toMatch >= find) 
      { 
       upper = toMatch; 
       break; 
      } 
     } 

     var end1 = (DateTime.Now - start1).TotalMilliseconds; 

     Console.WriteLine(end1 + " = " + upper); 
    } 

感謝

+0

我相信這是一個可以在這裏重複 點擊查看[複製] [1] [1]:http://stackoverflow.com/questions/44220/difference-between- foreach-for-loops-over-an-enumerable-class-in-c-sharp – SpaceApple 2013-03-04 15:27:13

+3

順便說一句,使用'Stopwatch'類。 – SLaks 2013-03-04 15:27:45

+0

你爲什麼從'if'中斷? – Ofiris 2013-03-04 15:28:18

回答

43

IEnumerable<T>不可索引。

Count()ElementAt()您在for循環的每次迭代中調用的擴展方法都是O(n);他們需要遍歷集合來查找count或第n個元素。

道德:知道你的收藏類型。

+9

+1 *爲道德*部分 – 2013-03-04 15:31:13

+0

注意'Count()'值得注意的是它取決於實際的集合類型,如果它使用Count屬性實現ICollection Count()將使用它 – sll 2013-03-04 15:42:59

+1

@sll:對於'元素也是。如果OP在'Select'之後添加一個'.ToArray()',那麼最大的區別就會消失。 – 2013-03-04 15:47:07

12

這樣做的原因不同的是,你的for循環將在每次迭代執行。這對您來說確實很貴,因爲它會執行Select並迭代完整的結果集。

此外,您正在使用ElementAt,它再次執行select並將其迭代到您提供的索引。