Каков наиболее эффективный способ объединения строк?
c#
.net
string
optimization
jimmij
источник
источник
StringBuilder
случаях использования можно найти здесь .String.Format
на стероидах. Который, с точки зрения производительности, немного медленнее на одной линии, чем+
иString.Concat
, но намного лучше, чем те, хотя и медленнее, чемStringBuilder
на нескольких вызовах. Практически говоря, различия в производительности таковы, что, если бы мне пришлось выбирать только один способ объединения, я бы выбрал интерполяцию строк, используя$
... Если два пути, то добавьтеStringBuilder
в свой набор инструментов. С этими двумя способами вы настроены.String.Join
Ответ ниже не делает+
справедливость и, практически говоря, плохой путь для конкатенации строк, но это удивительно высокая производительность мудрого. Ответ почему интересно.String.Concat
иString.Join
могут оба действовать на массивы, ноString.Join
на самом деле быстрее. По-видимому,String.Join
он довольно сложный и более оптимизированный, чемString.Concat
частично, потому что он работает аналогично тому,StringBuilder
что сначала вычисляет длину строки, а затем строит строку, извлекая пользу из этого знания, используя UnSafeCharBuffer.String.Join
также требует создания массива, который кажется неэффективным с точки зрения ресурсов, верно? ... Получается,+
иString.Concat
в любом случае строит массивы для их составляющих. Следовательно, создание массива вручную и его подачаString.Join
выполняется сравнительно быстрее ... однако, он по-StringBuilder
прежнему превосходитString.Join
практически все практические способы, хотя$
лишь немного медленнее и намного быстрее на длинных строках ... не говоря уже о том, что его неудобно и некрасиво использовать,String.Join
если у вас есть создать массив для него на месте.Ответы:
Этот
StringBuilder.Append()
метод намного лучше, чем использование+
оператора. Но я обнаружил, что при выполнении 1000 конкатенаций или менее,String.Join()
это даже более эффективно, чемStringBuilder
.Единственная проблема в
String.Join
том, что вам нужно объединить строки с общим разделителем.Изменить: как указал @ryanversaw , вы можете сделать разделитель
string.Empty
.источник
StringBuilder
имеет огромную сопоставимую стоимость запуска, он эффективен только при использовании с очень большими строками или очень большим количеством конкатенаций. Это не тривиально, чтобы выяснить для любой конкретной ситуации. Если производительность является проблемой, профилирование - ваш друг (проверьте ANTS).string.Concat
?Рико Мариани , гуру .NET Performance, написал статью на эту тему. Это не так просто, как можно подозревать. Основной совет заключается в следующем:
Еще одна статья, подтверждающая это утверждение, написана Эриком Липпертом, в котором он подробно описывает оптимизацию, выполненную для
+
конкатенаций в одну строку .источник
Существует 6 типов конкатенации строк:
+
символ плюс ( ).string.Concat()
.string.Join()
.string.Format()
.string.Append()
.StringBuilder
.В эксперименте было доказано, что
string.Concat()
это лучший способ приблизиться, если слова меньше 1000 (приблизительно) и если слова больше 1000, тогдаStringBuilder
следует использовать.Для получения дополнительной информации, проверьте этот сайт .
источник
+
самом деле это было на 3 миллисекунды быстрееstring.Concat()
, хотя я не изучал количество строк, необходимых передstring.Concat()
расправой+
.От Chinh Do - StringBuilder не всегда быстрее :
Эмпирические правила
При объединении трех динамических строковых значений или менее используйте традиционную конкатенацию строк.
При объединении более трех динамических строковых значений используйте
StringBuilder
.При построении большой строки из нескольких строковых литералов используйте
@
строковый литерал или оператор inline +.Большую часть времени
StringBuilder
это ваша лучшая ставка, но в этом посте, как показано в некоторых случаях, вы должны хотя бы подумать о каждой ситуации.источник
Если вы работаете в цикле,
StringBuilder
вероятно, это путь; это избавляет вас от необходимости регулярно создавать новые строки. В коде, который будет запускаться только один раз, возможно,String.Concat
это нормально.Однако Рико Мариани (гуру оптимизации .NET) составил викторину, в которой он в конце заявил, что в большинстве случаев он рекомендует
String.Format
.источник
Вот самый быстрый метод, который я развил за десятилетие для моего крупномасштабного приложения НЛП. У меня есть варианты для
IEnumerable<T>
и других типов ввода, с и без разделителей разных типов (Char
,String
), но здесь я показываю простой случай объединения всех строк в массиве в одну строку без разделителя. Последняя версия здесь разработана и протестирована на C # 7 и .NET 4.7 .Есть два ключа для повышения производительности; Во-первых, необходимо предварительно рассчитать точный общий требуемый размер. Этот шаг является тривиальным, когда вход представляет собой массив, как показано здесь. Для обработки
IEnumerable<T>
вместо этого стоит сначала собрать строки во временный массив для вычисления этой общей суммы (массив требуется, чтобы избежать вызоваToString()
более одного раза на элемент, так как технически, учитывая возможность побочных эффектов, это может изменить ожидаемую семантику операции 'string join').Далее, с учетом общего размера выделения последней строки, наибольшее повышение производительности достигается путем создания строки результата на месте . Для этого требуется (возможно, противоречивая) техника временной приостановки неизменности нового,
String
который изначально выделен полными нулями. Любой такой спор в стороне, однако ...Полный код:
Я должен отметить, что этот код имеет небольшие изменения по сравнению с тем, что я использую сам. В оригинале, я называю cpblk IL инструкции от C # для фактического копирования. Для простоты и переносимости кода здесь
memcpy
, как вы можете видеть , я заменил его на P / Invoke . Для достижения максимальной производительности на x64 ( но, возможно, не на x86 ) вы можете вместо этого использовать метод cpblk .источник
string.Join
делает все эти вещи уже для вас. Там нет необходимости писать это самостоятельно. Он вычисляет размер последней строки, создает строку этого размера и затем записывает в базовый массив символов. У этого даже есть бонус использования читаемых имен переменных в процессе.String.Join
может быть эффективным. Как я уже говорил во введении, код здесь - просто простейшая иллюстрация семейства функций, которые я использую для сценариев, которыеString.Join
либо не обрабатываются (например, оптимизируются дляChar
разделителя), либо не обрабатывались в предыдущих версиях .NET. Я полагаю, что я не должен был выбирать это для простейшего примера, так как это случай, которыйString.Join
уже хорошо справляется, хотя и с «неэффективностью», вероятно, неизмеримой, обработки пустого разделителя, а именно.String.Empty
,Concat
, что также делает это правильно. В любом случае вам не нужно писать код самостоятельно.String.Join
с моим кодом, используя этот тестовый комплект . Для 10 миллионов операций произвольной конкатенации, каждая из которых содержит до 100 строк размером с слово, приведенный выше код всегда на 34% быстрее, чемString.Join
в сборке x64 с .NET 4.7 . Поскольку OP явно запрашивает «самый эффективный» метод, результат предполагает, что мой ответ применим. Если это решит ваши проблемы, я приглашаю вас пересмотреть свое отрицательное мнение.Из этой статьи MSDN :
Так что, если вы доверяете MSDN, используйте StringBuilder, если вам нужно выполнить более 10 операций / конкатенаций строк - в противном случае простая конкататация строк с «+» подойдет.
источник
Также важно указать, что вы должны использовать
+
оператор, если объединяете строковые литералы .Как: объединить несколько строк (Руководство по программированию в C #)
источник
Добавляя к другим ответам, имейте в виду, что StringBuilder может указать начальный объем памяти для выделения .
Повторное добавление в StringBuilder, который не был предварительно выделен, может привести к большому количеству ненужных выделений, как многократное объединение обычных строк.
Если вы знаете, какой длины будет последняя строка, можете легко ее вычислить или можете сделать обоснованное предположение об общем случае (выделение слишком большого количества данных не обязательно является плохой вещью), вам следует предоставить эту информацию конструктору или Емкость свойство. Особенно при запуске тестов производительности для сравнения StringBuilder с другими методами, такими как String.Concat, которые делают то же самое внутри. Любой тест, который вы видите в сети и который не включает предварительное распределение StringBuilder в своих сравнениях, неверен.
Если вы не можете догадаться о размере, вы, вероятно, пишете служебную функцию, которая должна иметь собственный необязательный аргумент для управления предварительным распределением.
источник
Ниже может быть еще одно альтернативное решение для объединения нескольких строк.
интерполяция строк
источник
String.Format
но более читабельно и с ним легче работать. Разметка его, это немного медленнее , чем+
иString.Concat
на одной линии сцеплений , но гораздо лучше , чем оба из тех , при повторных вызовах делаетStringBuilder
менее необходимым.Наиболее эффективным является использование StringBuilder, например так:
@jonezy: String.Concat - это хорошо, если у вас есть пара небольших вещей. Но если вы объединяете мегабайты данных, ваша программа, скорее всего, будет работать.
источник
Попробуйте это 2 куска кода, и вы найдете решение.
Vs
Вы обнаружите, что первый код закончится очень быстро, и память будет в хорошем количестве.
Второй код, возможно, память будет в порядке, но это займет больше времени ... намного дольше. Так что, если у вас есть приложение для большого количества пользователей и вам нужна скорость, используйте 1-й. Если у вас есть приложение для краткосрочного однопользовательского приложения, возможно, вы можете использовать оба, или второе будет более «естественным» для разработчиков.
Приветствия.
источник
Только для двух строк вы определенно не хотите использовать StringBuilder. Существует некоторый порог, выше которого накладные расходы StringBuilder меньше накладных расходов на выделение нескольких строк.
Итак, для более чем 2-3 строк используйте код DannySmurf . В противном случае просто используйте оператор +.
источник
System.String является неизменным. Когда мы изменяем значение строковой переменной, то новому значению выделяется новая память, а предыдущее выделение памяти освобождается. System.StringBuilder был разработан, чтобы иметь концепцию изменяемой строки, где различные операции могут выполняться без выделения отдельного места в памяти для измененной строки.
источник
Другое решение:
внутри цикла используйте список вместо строки.
это очень очень быстро.
источник
Это действительно зависит от вашей модели использования. Подробный тест между string.Join, string, Concat и string.Format можно найти здесь: String.Format не подходит для интенсивной регистрации
(На самом деле это тот же ответ, который я дал на этот вопрос)
источник
Это будет зависеть от кода. Обычно StringBuilder более эффективен, но если вы объединяете только несколько строк и делаете все это в одной строке, оптимизация кода, скорее всего, позаботится об этом за вас. Важно также подумать о том, как выглядит код: для больших наборов StringBuilder облегчит чтение, для маленьких StringBuilder просто добавит ненужный беспорядок.
источник