Я тестирую различия в производительности, используя различные лямбда-выражения синтаксисы выражений. Если у меня есть простой метод:
public IEnumerable- GetItems(int point)
{
return this.items.Where(i => i.IsApplicableFor(point));
}
, то здесь происходит некоторый подъем переменной, связанный с параметром point
, потому что это свободная переменная с точки зрения лямбда. Если бы я вызвал этот метод миллион раз, было бы лучше оставить его как есть или изменить его каким-либо образом, чтобы улучшить его производительность?
Какие варианты у меня есть и какие реально осуществимы? Насколько я понимаю, я должен избавиться от бесплатные переменные, поэтому компилятору не нужно будет создавать закрывающий класс и создавать его экземпляр при каждом вызове этого метода. Это создание экземпляра обычно занимает значительное время по сравнению с версиями без закрытия.
Дело в том, что я хотел бы придумать своего рода руководящие принципы написания лямбда , которые обычно работают, потому что кажется, что я зря трачу каждый раз, когда я пишу сильно удачное лямбда-выражение. Мне нужно вручную протестировать его, чтобы убедиться, что он будет работать, потому что я не знаю, каким правилам следовать.
Я также написал другую версию того же метода, который не требует подъема переменных (по крайней мере, я думаю, что нет, но вы, ребята, поймите это, дайте мне знать, если это так):
public IEnumerable- GetItems(int point)
{
Func
> buildPredicate = p => i => i.IsApplicableFor(p);
return this.items.Where(buildPredicate(point));
}
Посмотрите Gist здесь .Просто создайте консольное приложение и скопируйте весь код в файл Program.cs
внутри блока namespace
. Вы увидите, что второй пример намного медленнее, даже если он не использует свободные переменные.
Причина, по которой я хотел бы составить некоторые рекомендации по наилучшему использованию лямбда , заключается в том, что я столкнулся с этой проблемой до и, к моему удивлению, чтобы работать быстрее при использовании лямбда-выражения построителя предикатов .
Теперь объясните это тогда. Я полностью потерялся здесь, потому что может оказаться, что я вообще не буду использовать лямбды, когда знаю, что в моем коде есть какой-то метод интенсивного использования. Но хотелось бы избежать такой ситуации и разобраться во всем.
Я пробовал реализовать собственный класс поиска, который внутренне работает так же, как компилятор со свободной переменной лямбда. Но вместо класса закрытия я реализовал члены экземпляра, которые имитируют аналогичный сценарий. Это код:
private int Point { get; set; }
private bool IsItemValid(Item item)
{
return item.IsApplicableFor(this.Point);
}
public IEnumerable GetItems(int point)
{
this.Point = point;
return this.items.Where(this.IsItemValid);
}
Интересно, что это работает так же медленно, как и медленная версия. Я не знаю почему, но, похоже, он не делает ничего, кроме быстрого. Он повторно использует ту же функциональность, потому что эти дополнительные члены являются частью одного и того же экземпляра объекта. В любом случае. Я очень запутался !
Я обновил источник Gist этим последним дополнением, так что вы можете проверить это сами.