2009-06-25 5 views

ответ

55

Напишите самый чистый код, который вы можете, а затем сравнительный анализ и профиль, чтобы обнаружить любые проблемы с производительностью. Если у вас есть do, у вас есть проблемы с производительностью, вы можете поэкспериментировать с другим кодом, чтобы решить, быстрее или не работает (все время измеряйте как можно более реалистичные данные), а затем выносите суждение о том, стоит ли повышение производительности читаемость.

Прямой foreach подход будет быстрее, чем LINQ во многих случаях. Например, рассмотрит:

var query = from element in list 
      where element.X > 2 
      where element.Y < 2 
      select element.X + element.Y; 

foreach (var value in query) 
{ 
    Console.WriteLine(value); 
} 

В настоящее время существует два where положения и пункт select, поэтому каждый конечный пункт должен пройти через три итераторы. (. Очевидно, что два положения, где можно было бы объединить в этом случае, но я готовлю общую точку)

Теперь сравните его с прямым кодом:

foreach (var element in list) 
{ 
    if (element.X > 2 && element.Y < 2) 
    { 
     Console.WriteLine(element.X + element.Y); 
    } 
} 

Это будет работать быстрее, так как он имеет меньшее количество обручей. Скорее всего, консольный вывод будет затмевать стоимость итератора, и я бы предпочел запрос LINQ.

EDIT: Для того, чтобы ответить о «вложенном Еогеаспе» петля ... обычно те, которые представлены с SelectMany или вторым from пунктом:

var query = from item in firstSequence 
      from nestedItem in item.NestedItems 
      select item.BaseCount + nestedItem.NestedCount; 

Здесь мы только добавление одного дополнительного итератором, потому что мы d уже использует дополнительный итератор для каждого элемента в первой последовательности из-за вложенного цикла foreach. Все еще немного накладных расходов, в том числе накладные расходы на выполнение проекции в делегате вместо «встроенного» (что-то, о чем я не упоминал ранее), но он все равно не будет сильно отличаться от производительности вложенных-foreach.

Это не значит, что вы не можете стрелять в ногу с помощью LINQ, конечно. Вы можете писать безупречно неэффективные запросы, если сначала не занимаетесь своим мозгом, но это далеко не уникально для LINQ ...

+13

Первое предложение должно быть распечатано как баннер и помещено в каждый отдел программирования. –

+1

Джон ... Ты потрясающий ... Сердечно спасибо! –

11

Это более сложный вопрос. В конечном счете, большая часть LINQ-to-Objects (за кулисами) имеет цикл foreach, но с дополнительными издержками небольших блоков абстракции/итератора/и т. Д. Однако, если вы не делаете очень разные вещи в своих двух версиях (foreach vs LINQ), они должны быть как O (N).

Реальный вопрос: есть ли лучший способ написать ваш конкретный алгоритм, что означает, что foreach будет неэффективным? И может ли LINQ сделать это за вас?

Например, LINQ позволяет легко хешировать/группировать/сортировать данные.

22

Если вы

foreach(Customer c in Customer) 
{ 
    foreach(Order o in Orders) 
    { 
    //do something with c and o 
    } 
} 

Вы выполнить Customer.Count заказ *.Количество итераций


Если вы делаете

var query = 
    from c in Customer 
    join o in Orders on c.CustomerID equals o.CustomerID 
    select new {c, o} 

foreach(var x in query) 
{ 
    //do something with x.c and x.o 
} 

Вы выполнять итерации Customer.Count + Order.Count, потому что Enumerable.Join реализуется как HashJoin.

+0

отличный ответ с хорошим объяснением –

+4

Это потому, что вы используете два разных алгоритма; вы сравниваете яблоки с апельсинами. Я не вижу, как это имеет отношение к поставленному вопросу. – mquander

+3

Ваш вложенный foreach на самом деле эквивалентен SelectMany, а не Join - i.e. from c в Customer from o в Orders ... (нет соединения) –

2

Это было сказано ранее, но это заслуживает повторения.

Разработчики никогда не знают, где узкое место производительности до тех пор, пока они не проведут тесты производительности.

То же самое верно для сравнения техники A с техникой B. Если нет существенной разницы, вам просто нужно ее протестировать. Это может быть очевидно, если у вас есть сценарий O (n) vs O (n^x), но поскольку материал LINQ в основном является компилятором, он заслуживает профилирования.

Кроме того, если ваш проект не находится в производстве, и вы профилировали код и обнаружили, что этот цикл замедляет выполнение, оставьте его в зависимости от вашего предпочтения для удобства чтения и обслуживания. Преждевременная оптимизация - дьявол.

+1

Хотя верно, что вы не можете по-настоящему предвидеть узкие места в производительности, также верно, что большинство проблем с производительностью разработаны, они находятся очень поздно в жизненном цикле разработки и поэтому трудно кодировать. Существует много всего, что нужно сказать, чтобы всегда иметь представление о последствиях решений решений по дизайну и реализации, которые вы делаете, а не беспечно кодировать, надеясь, что все будет в порядке. – Mike

2

Большое преимущество заключается в том, что использование запросов Linq-To-Objects дает возможность легко перевести запрос на PLinq и система автоматически выполнит его работу с правильным количеством потоков для текущей системы.

Если вы используете эту технику на больших наборах данных, это легко станет большой победой для очень маленьких неприятностей.

+0

Правда, но есть и параллельные эквиваленты, предложенные для foreach. http://www.danielmoth.com/Blog/2009/01/parallelising-loops-in-net-4.html – jpierson

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

  • Нет связанных вопросов^_^