Есть ли у кого-нибудь совет по использованию параметров в С# для передачи аргумента метода. Я подумываю о перегрузке первых 6 аргументов, а затем 7-го, используя функцию params. Мое рассуждение состоит в том, чтобы избежать дополнительного выделения массива, требуемого функцией params. Это для некоторых высокопроизводительных служебных методов. Любой совет? Это пустая трата кода на создание всех перегрузок?
Стоимость использования параметров в C#
Ответы (6)
Честно говоря, меня немного напрягает, что все кричат "преждевременная оптимизация!" Вот почему.
- То, что вы говорите, имеет смысл, особенно поскольку вы уже указали, что работаете над высокопроизводительной библиотекой.
- Даже классы BCL следуют этому образцу. Рассмотрим все перегрузки
string.Format
илиConsole.WriteLine
. - Это очень легко сделать правильно. Вся предпосылка, стоящая за движением против преждевременной оптимизации, заключается в том, что когда вы делаете что-то хитрое в целях оптимизации производительности, вы можете случайно что-то сломать и сделать свой код менее ремонтопригодна. Я не вижу в этом опасности; то, что вы делаете, должно быть очень простым как для вас самих, так и для любого будущего разработчика, который может иметь дело с вашим кодом.
Кроме того, даже если вы профилировали результаты обоих подходов и увидели лишь очень небольшую разницу в скорости, проблема с выделением памяти остается. Создание нового массива для каждого вызова метода влечет за собой выделение большего объема памяти, которая позже потребуется для сборки мусора. А в некоторых сценариях, где желательно поведение «почти» в реальном времени (например, алгоритмическая торговля, поле Я), минимизация сбора мусора так же важна, как и максимальная скорость выполнения.
Так что, даже если это принесет мне несколько отрицательных голосов: я говорю, дерзайте.
(А тем, кто утверждает, что «компилятор наверняка уже делает что-то подобное» — я бы не был так уверен. Во-первых, если бы это было так, я не понимаю, почему классы BCL следовали бы этому шаблону, поскольку я уже упоминалось. Но что более важно, существует очень большая семантическая разница между методом, который принимает несколько аргументов, и методом, который принимает массив. Просто потому, что один может< /em> используется вместо другого не означает, что компилятор будет или должен попытаться выполнить такую замену).
Да, это стратегия, которую использует платформа .NET. String.Concat() будет хорошим примером. Он имеет перегрузки до 4 строк, а также резервную версию, которая принимает строку параметров []. Здесь довольно важно то, что Concat должен быть быстрым и помочь пользователю упасть в яму успеха, когда он использует оператор + вместо StringBuilder.
Дублирование кода, которое вы получите, — это цена. Вы бы профилировали их, чтобы увидеть, стоит ли ускорение головной боли обслуживания.
Fwiw: в среде .NET существует множество подобных микрооптимизаций. В некоторой степени необходимо, потому что дизайнеры не могли предсказать, как будут использоваться их классы. String.Concat() с такой же вероятностью будет использоваться в тесном внутреннем цикле, который имеет решающее значение для производительности программы, как, скажем, считыватель конфигурации, который запускается только один раз при запуске. Как конечный пользователь собственного кода вы обычно можете позволить себе не беспокоиться об этом. Верно и обратное: код платформы .NET на удивление свободен от микрооптимизаций, когда маловероятно, что их выгода будет измерима. Например, предоставление перегрузок, когда основной код все равно работает медленно.
Вы всегда можете передать Tuple
в качестве параметра или, если типы параметров всегда одинаковы, IList<T>
.
Как уже говорилось в других ответах и комментариях, вы должны оптимизировать только после:
- Обеспечение правильного поведения.
- Определение необходимости оптимизации.
Я хочу сказать, что если ваш метод способен получать неограниченное количество параметров, то логика внутри него работает в стиле массива. Таким образом, перегрузки для ограниченного числа параметров не помогут. Если только вы не можете реализовать ограниченное количество параметров совершенно другим способом, который намного быстрее.
Например, если вы передаете параметры в Console.WriteLine, там также создается скрытый массив, так что в любом случае у вас будет массив.
И, извините за беспокойство Дэна Тао, я также чувствую, что это преждевременная оптимизация. Потому что вам нужно знать, какая разница будет иметь перегрузки с ограниченным количеством параметров. Если ваше приложение настолько критично к производительности, вам нужно реализовать оба способа и попытаться запустить тест и сравнить время выполнения.
Даже не думайте о производительности на этом этапе. Создавайте любые перегрузки, которые сделают ваш код проще для написания и понимания в 4 утра через два года. Иногда это означает параметры, иногда это означает их избегание.
После того, как у вас есть что-то, что работает, выясните, не является ли это проблемой производительности. Нетрудно сделать параметры более сложными, но если вы добавите ненужную сложность сейчас, вы никогда не сделаете их менее такими позже.
Вы можете попробовать что-то вроде это, чтобы оценить производительность, чтобы у вас были конкретные цифры для принимать решения с.
В общем, выделение объектов происходит немного быстрее, чем в C/C++, а удаление небольших объектов происходит гораздо быстрее — до тех пор, пока у вас не будет десятков тысяч таких объектов в секунду. Вот старая статья о производительности выделения памяти.
System.String.Format()
. - person Jeff Mercado   schedule 17.10.2010