Только для чтения Func по сравнению с методами, последствиями для производительности/внутренними вещами

Есть ли какие-либо последствия для производительности при реализации ссылочно-прозрачных методов как статических функций только для чтения, а не просто как методов? Лично я нахожу версии Func более читабельными, но, возможно, традиционный способ более эффективен.

Этот:

static readonly Func<DateTime, DateTime> TruncateDay =
  date => date.AddHours(-date.Hour)
              .AddMinutes(-date.Minute)
              .AddSeconds(-date.Second)
              .AddMilliseconds(-date.Millisecond);

static readonly Func<DateTime, DateTime> TruncateMonth =
  date => TruncateDay(date).AddDays(1 - date.Day);

static readonly Func<DateTime, DateTime> TruncateYear =
  date => TruncateMonth(date).AddMonths(1 - date.Month);

static readonly Func<DateTime, int> QuarterSwitch =
  date => Switch(date.Month % 3, 0,
            Case(1, 3),
            Case(2, 4),
            Case(0, 5));

По сравнению с этим:

static DateTime TruncateDay (DateTime date) 
{ 
  return date.AddHours(-date.Hour)
             .AddMinutes(-date.Minute)
             .AddSeconds(-date.Second)
             .AddMilliseconds(-date.Millisecond);
}

static DateTime TruncateMonth (DateTime date)
{ 
  return TruncateDay(date).AddDays(1 - date.Day);
}

static DateTime TruncateYear (DateTime date)
{
  return TruncateMonth(date).AddMonths(1 - date.Month);
}

static int QuarterSwitch (DateTime date)
{ 
  return Switch(date.Month % 3, 0,
           Case(1, 3),
           Case(2, 4),
           Case(0, 5));
}

Как они представлены внутри? Во что транслирует каждый из них компилятор?


person TheIronKnuckle    schedule 22.01.2012    source источник
comment
Я бы сказал, что нет, потому что делегаты — это делегаты, а методы — это методы. как только вы объявляете метод, он не может быть ничем другим. В то время как делегаты могут изменить метод, на который они указывают, в любое время. Мой вопрос не о делегатах.   -  person TheIronKnuckle    schedule 23.01.2012
comment
Меня также больше интересует, что быстрее, и различия между ними под капотом, а не преимущества / недостатки.   -  person TheIronKnuckle    schedule 23.01.2012
comment
К вашему сведению, TruncateDay уже существует как свойство Date для значения DateTime и примерно в 5 раз быстрее, чем ваша реализация. См. msdn.microsoft.com/en-us/library/system. .datetime.date.aspx   -  person Jeffrey Sax    schedule 26.01.2012
comment
Ах, спасибо! Я долго искал, прежде чем прибегнуть к этому. Не могу поверить, что я пропустил это.   -  person TheIronKnuckle    schedule 26.01.2012


Ответы (4)


Под капотом компилятор создает 2 дополнительных члена для каждого метода Func:

  1. Статический метод, по сути такой же, как и в традиционном подходе.
  2. Поле «кэшированного делегата» того же типа, что и ваш делегат.

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

Классу также требуется статический конструктор для инициализации этих двух полей для каждого метода.

Вот некоторые из последствий для производительности:

  • При вызове частной статической функции возникают небольшие накладные расходы. Эти накладные расходы увеличиваются по мере увеличения размера списка аргументов.
  • Func методы никогда не могут быть встроенными. Это может иметь большое значение для очень маленьких методов.
  • Метаданные для вашего класса будут примерно в 3 раза больше. Это не бесплатно, но его последствия трудно оценить количественно.

Некоторые из других недостатков использования этого:

  • Перегрузка невозможна.
  • Имена параметров не подхватываются в Intellisense.
  • Это нарушает ожидания несколькими способами, включая тот факт, что методы отображаются как поля в списке завершения операторов.
person Jeffrey Sax    schedule 25.01.2012

Попробовав ваш TruncateDay в простом цикле, я получил метод, который стал немного быстрее — достаточно близко, чтобы самые медленные запуски с методом были медленнее, чем самые быстрые с делегатом, но все же почти последовательно, что делегат имел тенденцию быть просто немного менее производительный.

Затем я попробовал версию, которая просто возвращает переданное ей значение. Мой план состоял в том, чтобы иметь метод, который определенно должен быть встраиваемым, и версия метода была примерно в 5 раз быстрее, чем версия делегата. Очевидный вывод состоит в том, что метод действительно был встроен, а делегат — нет, хотя это, конечно, предположение.

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

person Jon Hanna    schedule 22.01.2012
comment
Сбор эмпирических данных. Какого черта? :) - person Andrew Steitz; 02.11.2017
comment
Конечно, поскольку теперь у нас есть синтаксис тела выражения, любой, кто находит синтаксис в вопросе более читаемым, скорее всего, найдет его еще более читаемым, так что, по крайней мере, причина больше не в том, чтобы делать то, что было. - person Jon Hanna; 02.11.2017

Статические методы будут намного быстрее, если сами их тела будут дешевыми. Если тело дорогое не беда.

JIT не может встроить содержимое делегата и должен использовать косвенный вызов. И то, и другое ужасно (для дешевых методов).

Кроме того, с точки зрения качества кода это неприемлемо:

  • Больше кода
  • Для большинства людей менее читабелен, потому что они привыкли к традиционному стилю
  • Нет поддержки рефакторинга
  • Против традиционных идиом
  • Более сложный

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

person usr    schedule 25.01.2012
comment
+1, также это были бы хорошие методы расширения, что возможно только в том случае, если они... методы. - person Meta-Knight; 25.01.2012
comment
Почему за это проголосовали? Я ответил на вопрос, и вдобавок дал совет по архитектуре. Это вежливость, чтобы оставить комментарий, почему вы проголосовали против. - person usr; 27.01.2012
comment
Я полностью согласен с вашей оценкой и не согласен с отрицательным голосом, тем более, что комментарий не был предоставлен. Итак... Я проголосовал за смещение. :) - person Andrew Steitz; 02.11.2017

Это помогает мне. Надеюсь, это сделает то же самое для вас.

grid.Sort.Enabled = false;
grid.Data Source = _data source_;

//Add a single object to the beginning of the grid
grid.Nodes.Insert(0, _new_object_);

//Add a single object to the beginning of the binding list
I Binding List bl = ...;
bl.Insert(0, _new_object_); 
person Community    schedule 12.06.2012