Стоимость использования params в C # - PullRequest
20 голосов
/ 17 октября 2010

У кого-нибудь есть советы по использованию параметров в C # для передачи аргументов метода. Я собираюсь сделать перегрузки для первых 6 аргументов, а затем для 7-го с использованием функции params. Я считаю, что нужно избегать дополнительного выделения массива, которое требуется для функции params. Это для некоторых высокопроизводительных служебных методов. Любой совет? Это пустая трата кода для создания всех перегрузок?

Ответы [ 6 ]

54 голосов
/ 17 октября 2010

Честно говоря, я немного обеспокоен тем, что все кричат ​​"преждевременная оптимизация!" И вот почему.

  1. То, что вы говорите, имеет смысл, особенно , как вы уже указали, вы работаете над высокопроизводительной библиотекой.
  2. Даже классы BCL следуют этой схеме. Учитывайте все перегрузки string.Format или Console.WriteLine.
  3. Это очень легко понять . Вся причина движения против преждевременной оптимизации заключается в том, что когда вы делаете что-то хитрое в целях оптимизации производительности, вы можете случайно что-то сломать и сделать свой код менее понятным , Я не вижу, как это опасно здесь; это должно быть очень просто для вас, как для себя, так и для любого будущего разработчика, который может работать с вашим кодом.

Кроме того, даже если вы профилировали результаты обоих подходов и видели только очень небольшую разницу в скорости, все равно остается проблема выделения памяти. Создание нового массива для каждого вызова метода влечет за собой выделение большего объема памяти, которая впоследствии потребуется для сборки мусора. А в некоторых сценариях, где желательно «почти» поведение в реальном времени (например, алгоритмическая торговля, поле I'm in), минимизация сборок мусора так же важна, как и максимизация скорости выполнения.

Так что, даже если это принесет мне несколько отрицательных голосов: я говорю, дерзайте.

(И тем, кто утверждает, что «компилятор наверняка уже делает что-то подобное» - я бы не был так уверен. Во-первых, если бы это было так, я не понимаю, почему классы BCL следовали бы этому шаблону, так как Я уже упоминал. Но что более важно, существует очень большая семантическая разница между методом, который принимает несколько аргументов , и методом, который принимает массив . Просто потому, что один может использование в качестве замены для другого не означает, что компилятор или должен предпринять попытку такой замены).

15 голосов
/ 17 октября 2010

Да, именно эту стратегию использует .NET Framework. String.Concat () будет хорошим примером. Он имеет перегрузки для до 4 строк, плюс запасной, который принимает строку параметров []. Довольно важно, что Concat должен быть быстрым и помочь пользователю попасть в пропасть успеха, когда он использует оператор + вместо StringBuilder.

Дублирование кода, которое вы получите, является ценой. Вы бы профилировали их, чтобы увидеть, стоит ли ускорение головной боли при обслуживании.

Замечу: в платформе .NET существует множество микрооптимизаций, подобных этой. В некоторой степени это необходимо, потому что дизайнеры не могли предсказать, как будут использоваться их классы. String.Concat () с такой же вероятностью будет использоваться в узком внутреннем цикле, который критичен для выполнения программ, как, скажем, программа чтения конфигурации, которая запускается только один раз при запуске. Как конечный пользователь вашего собственного кода, вы обычно можете позволить себе не беспокоиться об этом. Также верно и обратное: код платформы .NET удивительно свободен от микрооптимизаций, когда маловероятно, что их выгода будет ощутимой. Как и обеспечение перегрузки, когда основной код работает медленно.

4 голосов
/ 17 октября 2010

Вы всегда можете передать Tuple в качестве параметра или, если типы параметров всегда одинаковы, IList<T>.

, как сказали другие ответы и комментарииВы должны оптимизировать только после:

  1. Обеспечение правильного поведения.
  2. Определение необходимо для оптимизации.
2 голосов
/ 17 октября 2010

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

Например, если вы передаете параметры в Console.WriteLine, там также есть скрытый массив,так что в любом случае у вас получится массив.

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

1 голос
/ 17 октября 2010

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

Как правило, распределение объектов выполняется немного быстрее, чем в C / C ++, а удаление небольших объектов намного, намного быстрее - до тех пор, пока вы не создадите десятки тысяч в секунду. Вот старая статья о производительности выделения памяти .

1 голос
/ 17 октября 2010

Даже не думайте о производительности на этом этапе. Создавайте любые перегрузки, чтобы ваш код было легче писать и легче было понять в 4 часа утра через два года. Иногда это означает params, иногда это означает избегать его.

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

...