2013-03-04 3 views
13

Я делал некоторые оптимизации для алгоритма, который находит наименьшее число, большее X, в данном массиве, но затем я наткнулся на странную разницу. В приведенном ниже коде «ForeachUpper» заканчивается на 625 мс, а «ForUpper» заканчивается, я считаю, несколько часов (безумно медленнее). Почему так?C# - For 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-and-for-loops-over-an-ienumerable-class-in-c-sharp – SpaceApple

+3

BTW, используйте класс «Секундомер». – SLaks

+0

Почему вы «ломаете» от 'if'? – Ofiris

ответ

43

IEnumerable<T> не подлежит индексированию.

Методы расширения, которые вы вызываете на каждой итерации вашего цикла for, равны O (n); они должны пройти через коллекцию, чтобы найти счетчик или n-й элемент.

Моральный: Знайте свои типы сбора.

+9

+1 для * морального * раздела –

+0

Regardign 'Count()' стоит отметить, что он зависит от фактического типа коллекции, если он реализует ICollection с свойством Count 'Count()' будет использовать его – sll

+1

@sll: Это верно для ' ElementAt' тоже. Большие различия исчезнут, если OP добавит '.ToArray()' после 'Select'. –

12

Причина этого различия состоит в том, что ваш for цикл будет выполняться на каждой итерации. Это действительно дорого в вашем случае, потому что он выполнит Select и повторит полный набор результатов.

Кроме того, вы используете ElementAt, который снова выполняет выбор и выполняет итерацию до указателя, который вы указали.

Смежные вопросы