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