2014-01-06 2 views
5

У меня есть вопрос, связанный с эффективностью, относительно LINQ и стандартного цикла foreach.Метод вызовов внутри LINQ select (эффективность)

У меня есть метод, который делает примерно следующее

var foos = users.Select(this.GenerateNullableFoo).Where(foo => foo != null); 

Это оказалось, по какой-то причине, чтобы быть чудовищно медленно. Используя временные метки, я смог определить, что точка медлительности была точно на итерации выбора (время от окончательного утверждения возврата до начала следующего вызова метода) была значительно медленнее (13 секунд), чем что-либо еще (общее время < = 14 секунд).

При замене на следующее время все время процесса сократилось до менее 1 секунды на итерацию.

Новый код:

var foos= new List<Foo>(); 

foreach (var user in users) 
{ 
    var foo = GenerateNullableFoo(user); 

     foo.IfNotNull(f => foos.Add(foo)); 
} 

Насколько я знаю, мой код работает, и нет ничего плохого с новым кодом, однако, я полностью сбит с толку, почему с помощью Select выше было больше чем в 10 раз медленнее, чем foreach, делающий, по-видимому, тот же самый процесс. Есть ли представление о том, какие различия могут объяснить это?

Кроме того, весь список не сохраняется до после. В нем указывается select/foreach, после чего в db выполняется пакетный вызов.

EDIT: Весь блок кода с точки начала до конца (и окончание) выглядит следующим образом:

//Code snippet pictured above 
_repo.SaveFoo(Foos); 
//at this point, the code terminates and is finished 
+3

Как вы используете запрос у вас? Если вы, например, повторяете результаты несколько раз, что легко объясняет поведение. – Servy

+7

Вы пробовали 'var foos = users.Select (this.GenerateNullableFoo) .Where (foo => foo! = Null)' * .ToList() * ';'? Это создаст код, который больше похож на 'foreach'. –

+0

Почему у вас есть 'foo! = Null' в верхнем и' foo.IfNotNull (..) 'внизу? –

ответ

1

Как уже говорилось, выражение LINQ не проецируется в наборе результатов, пока не будет итерация по коду, что означает, что все, что вы сделали, объявляет логику.

Код, который вы размещаете , а не, затем приводит к проецированию выражения LINQ и, скорее всего, много раз.

Самый короткий путь для решения этой проблемы просто добавить .ToList() к вашему выражению, это будет сразу же спроецировать выражение означает другой код можно использовать список в памяти и уже проецируется, не вызывая дополнительные прогнозы/расчеты/и т.д. и т. д.

Cheers, Aaron

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