2017-02-16 13 views
3

Предположим, что метод имеет необязательный аргумент Action или Func<T, T>, который обычно будет значением по умолчанию null. Это обычно выражение lambda-null будет вызываться много раз.Должны ли заменяемые аргументы лямбда заменить прозрачными реализациями?

В этой ситуации, это лучше:

  1. Null проверить лямбда-выражение перед каждым использованием, или ...

    а. Вызовите нулевое значение Action используя action?.Invoke().

    b. Преобразование с нулевым вызовом Func<T, T> - transform == null ? value : transform(value).

  2. ... null-проверить выражение один раз при вызове метода, а затем заменить его на прозрачный вариант?

    a. Заменить nullAction с new Action(() => { }).

    b. Заменить nullFunc<T, T> с new Func<T, T>((T value) => { return value; }).

Для этого вопроса, пожалуйста, предположим:

  • Это глубоко вложенным математике код, поэтому его производительность актуальна.

  • Читаемость кода не имеет существенного влияния.

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

Я предполагаю, что если выражение лямбда будет выполняться только один раз, тогда лучше всего всего null -учреждение в этой точке.

Но мне интересно, когда метод создает объект, который будет многократно называть лямбда-выражение. Предполагая, что аргумент обычно будет null, тогда, похоже, этот вопрос сводится к более простому вопросу: быстрее ли это null -Чтобы проверить лямбда или выполнить то, что ничего не делает?

+0

[Гонка ваших лошадей] (https://ericlippert.com/2012/12/17/performance-rant/) –

+0

@ RenéVogt Ха-ха, это хороший момент, и почему я указываю, что производительность важна в этот случай (поскольку люди часто спрашивают о производительности, когда это даже не имеет значения). Но, как отмечает EricLippert в этом блоге, трудно получить значащие тесты из собранной мусором, JIT-скомпилированной среды исполнения. Итак, я надеюсь на некоторое понимание общей природы выполнения прозрачной лямбды (может ли JIT оптимизировать ее в логике оптимизации мертвого кода?) По сравнению с нулевой проверкой (которая является ветвящейся операцией, которая может испортить Предсказатель ветвления процессора). [...] – Nat

+0

@ RenéVogt [...] И поскольку это сложный компромисс, который зависит от основных обобщений (например, как работает JIT-er и что влияет на предиктор отрасли процессора), я надеялся, что кто-то со знанием эти вопросы могли бы прокомментировать это. Хотя я подозреваю, что это может иметь существенное влияние, если один метод реализуется на протяжении всего проекта по сравнению с другим, я не уверен, что я получу значимые результаты, просто перейдя по одному по сравнению с другим методом быстрой проверки с помощью таймер прилагается. – Nat

ответ

0

3. использование пустого метода должно быть немного быстрее, чем создание новой пустой лямбды каждый раз:

static void _() { } 

static void b(Action a = null) 
{ 
    if (a == null) a = _; 
} 

4.чтобы избежать проверок Null

static void _() { } 

static void b() { b(_); } 

static void b(Action a) 
{ 

} 
+0

Создает ли .NET новый объект для новой лямбды каждый раз? Я знаю, что за кулисами выражение лямбда рассматривается как новое определение класса (называемое «DisplayClass» или что-то в этом роде), где локальный контекст по существу является параметром, который «DisplayClass» построен и хранится как поле. Но, когда ничего не зафиксировано, DisplayClass должен быть в основном статичным (как вы показали). Казалось бы, это плохая реализация, если .NET действительно создает новые экземпляры полностью статического класса каждый раз. – Nat

+0

@Nat Я бы рекомендовал сравнить сгенерированный ИЛ с http://ilspy.net, поскольку я не эксперт по внутренностям, но я не думаю, что компилятор может оптимизировать 'new Action (() => {})' также как 'static void _() {}' – Slai

1

Если вы проверяете this answer вы увидите некоторые тесты производительности для очень похожей проблемы делегата, хотя в данном случае это связанно с воспитывающими событиями:

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

Я предполагаю, что последствия для производительности будут схожими для вашего случая.