Каков наиболее эффективный способ объединения строк?
Этот StringBuilder.Append()
метод намного лучше, чем использование +
оператора. Но я обнаружил, что при выполнении 1000 конкатенаций или менее, String.Join()
это даже более эффективно, чем StringBuilder
.
StringBuilder sb = new StringBuilder();
sb.Append(someString);
Единственная проблема в String.Join
том, что вам нужно объединить строки с общим разделителем.
Изменить: как указал @ryanversaw , вы можете сделать разделитель string.Empty
.
string key = String.Join("_", new String[]
{ "Customers_Contacts", customerID, database, SessionID });
StringBuilder
имеет огромную сопоставимую стоимость запуска, он эффективен только при использовании с очень большими строками или очень большим количеством конкатенаций. Это не тривиально, чтобы узнать для любой конкретной ситуации. Если производительность является проблемой, профилирование - ваш друг (проверьте ANTS). string.Concat
? Наиболее эффективным является использование StringBuilder, например так:
StringBuilder sb = new StringBuilder();
sb.Append("string1");
sb.Append("string2");
...etc...
String strResult = sb.ToString();
@jonezy: String.Concat - это хорошо, если у вас есть пара небольших вещей. Но если вы объединяете мегабайты данных, ваша программа, скорее всего, будет работать.
Для двух строк вы определенно не хотите использовать StringBuilder. Существует некоторый порог, выше которого издержки StringBuilder меньше, чем накладные расходы на выделение нескольких строк.
Итак, для более чем 2-3 строк используйте код DannySmurf . В противном случае просто используйте оператор +.
От Chinh Do - StringBuilder не всегда быстрее :
Эмпирические правила
При объединении трех динамических строковых значений или менее используйте традиционную конкатенацию строк.
При объединении более трех динамических строковых значений используйте
StringBuilder
.При построении большой строки из нескольких строковых литералов используйте
@
строковый литерал или оператор inline +.
Большую часть времени StringBuilder
это ваша лучшая ставка, но в этом посте, как показано в некоторых случаях, вы должны хотя бы подумать о каждой ситуации.
Это будет зависеть от кода. Обычно StringBuilder более эффективен, но если вы объединяете только несколько строк и делаете все это в одной строке, оптимизация кода, скорее всего, позаботится об этом за вас. Важно также подумать о том, как выглядит код: для больших наборов StringBuilder облегчит чтение, для маленьких StringBuilder просто добавит ненужный беспорядок.
Если вы работаете в цикле, StringBuilder
вероятно, это путь; это избавляет вас от необходимости регулярно создавать новые строки. Впрочем, в коде, который запускается только один раз, String.Concat
это нормально.
Тем не менее, Рико Мариани (гуру оптимизации .NET) составил тест, в котором он в конце заявил, что в большинстве случаев он рекомендует String.Format
.
Рико Мариани , гуру .NET Performance, написал статью на эту тему. Это не так просто, как можно подозревать. Основной совет заключается в следующем:
Если ваш шаблон выглядит так:
x = f1(...) + f2(...) + f3(...) + f4(...)
это один конкат, и он быстрым, StringBuilder, вероятно, не поможет.
Если ваш шаблон выглядит так:
if (...) x += f1(...)
if (...) x += f2(...)
if (...) x += f3(...)
if (...) x += f4(...)
тогда вы, вероятно, хотите StringBuilder.
Еще одна статья, подтверждающая это утверждение, принадлежит Эрику Липперту, в котором он подробно описывает оптимизацию, выполняемую для +
конкатенаций в одну строку .
Из этой статьи MSDN :
С созданием объекта StringBuilder связаны некоторые накладные расходы, как по времени, так и по памяти. На машине с быстрой памятью стоит использовать StringBuilder, если вы выполняете около пяти операций. Как правило, я бы сказал, что 10 или более строковых операций являются оправданием накладных расходов на любой машине, даже более медленной.
Так что, если вы доверяете MSDN, используйте StringBuilder, если вам нужно выполнить более 10 операций / конкатенаций строк - в противном случае простая конкататация строк с «+» подойдет.
Это действительно зависит от вашей модели использования. Подробный тест между string.Join, string, Concat и string.Format можно найти здесь: String.Format не подходит для интенсивной регистрации
(На самом деле это тот же ответ, который я дал на этот вопрос)
Существует 6 типов конкатенации строк:
- Используя
+
символ плюс ( ). - Используя
string.Concat()
. - Используя
string.Join()
. - Используя
string.Format()
. - Используя
string.Append()
. - Используя
StringBuilder
.
В эксперименте было доказано, что string.Concat()
это лучший способ приблизиться, если слова меньше 1000 (приблизительно) и если слова больше 1000, тогда StringBuilder
следует использовать.
Для получения дополнительной информации, проверьте этот сайт .
string.Join () против string.Concat ()
Метод string.Concat здесь эквивалентен вызову метода string.Join с пустым разделителем. Добавление пустой строки - это быстро, но не делать это даже быстрее, поэтому здесь лучше использовать метод string.Concat .
+
самом деле это было на 3 миллисекунды быстрее string.Concat()
, хотя я не изучал количество строк, необходимых перед string.Concat()
расправой +
. Также важно указать, что вы должны использовать +
оператор, если объединяете строковые литералы .
Когда вы объединяете строковые литералы или строковые константы с помощью оператора +, компилятор создает одну строку. Конкатенация во время выполнения не происходит.
Как: объединить несколько строк (Руководство по программированию в C #)
System.String является неизменным. Когда мы изменяем значение строковой переменной, то новому значению выделяется новая память, а предыдущее выделение памяти освобождается. System.StringBuilder был разработан, чтобы иметь концепцию изменяемой строки, где различные операции могут выполняться без выделения отдельного места в памяти для измененной строки.
Добавляя к другим ответам, имейте в виду, что StringBuilder может сказать начальный объем памяти для выделения .
Параметр емкости определяет максимальное количество символов, которое может быть сохранено в памяти, выделенной текущим экземпляром. Его значение присваивается свойству Capacity . Если количество символов, которые будут сохранены в текущем экземпляре, превышает это значение емкости , объект StringBuilder выделяет дополнительную память для их хранения.
Если емкость равна нулю, используется емкость по умолчанию для конкретной реализации.
Повторное добавление в StringBuilder, который не был предварительно выделен, может привести к большому количеству ненужных выделений, как многократное объединение обычных строк.
Если вы знаете, какой длины будет последняя строка, можете легко ее вычислить или можете сделать обоснованное предположение об общем случае (выделение слишком большого количества данных не обязательно является плохой вещью), вам следует предоставить эту информацию конструктору или Емкость свойство. Особенно при запуске тестов производительности для сравнения StringBuilder с другими методами, такими как String.Concat, которые делают то же самое внутри. Любой тест, который вы видите в сети и который не включает предварительное распределение StringBuilder в своих сравнениях, неверен.
Если вы не можете догадаться о размере, вы, вероятно, пишете вспомогательную функцию, которая должна иметь собственный необязательный аргумент для управления предварительным распределением.
Попробуйте это 2 куска кода, и вы найдете решение.
static void Main(string[] args)
{
StringBuilder s = new StringBuilder();
for (int i = 0; i < 10000000; i++)
{
s.Append( i.ToString());
}
Console.Write("End");
Console.Read();
}
Vs
static void Main(string[] args)
{
string s = "";
for (int i = 0; i < 10000000; i++)
{
s += i.ToString();
}
Console.Write("End");
Console.Read();
}
Вы обнаружите, что первый код закончится очень быстро, и память будет в хорошем количестве.
Второй код, возможно, память будет в порядке, но это займет больше времени ... намного дольше. Так что, если у вас есть приложение для большого количества пользователей и вам нужна скорость, используйте 1-й. Если у вас есть приложение для краткосрочного однопользовательского приложения, возможно, вы можете использовать оба, или второе будет более «естественным» для разработчиков.
Приветствия.
Ниже может быть еще одно альтернативное решение для объединения нескольких строк.
String str1 = "sometext";
string str2 = "some other text";
string afterConcate = $"{str1}{str2}";
String.Format
но более читабельно и с ним легче работать. Разметка его, это немного медленнее , чем +
и String.Concat
на одной линии сцеплений , но гораздо лучше , чем оба из тех , при повторных вызовах делает StringBuilder
менее необходимым. Вот самый быстрый метод, который я развил за десятилетие для моего крупномасштабного приложения НЛП. У меня есть варианты для IEnumerable<T>
и других типов ввода, с и без разделителей различных типов ( Char
, String
), но здесь я показываю простой случай объединения всех строк в массиве в одну строку, без разделителя. Последняя версия здесь разработана и протестирована на C # 7 и .NET 4.7 .
Есть два ключа для повышения производительности; Во-первых, необходимо предварительно рассчитать точный общий требуемый размер. Этот шаг является тривиальным, когда вход представляет собой массив, как показано здесь. Для обработки IEnumerable<T>
вместо этого стоит сначала собрать строки во временный массив для вычисления этой общей суммы (массив требуется, чтобы не вызывать ToString()
более одного раза на элемент, так как технически, учитывая возможность побочных эффектов, это может изменить ожидаемую семантику операции 'string join').
Далее, с учетом общего размера выделения последней строки, наибольшее повышение производительности достигается путем создания строки результата на месте . Для этого требуется (возможно, противоречивая) техника временной приостановки неизменности нового, String
который изначально выделен полными нулями. Любой такой спор в стороне, однако ...
... Заметьте , что это единственный в массе конкатенации решение на этой странице полностью избегает дополнительный раунд выделения и копирования со стороны
String
конструктора.
Полный код:
/// <summary>
/// Concatenate the strings in 'rg', none of which may be null, into a single String.
/// </summary>
public static unsafe String StringJoin(this String[] rg)
{
int i;
if (rg == null || (i = rg.Length) == 0)
return String.Empty;
if (i == 1)
return rg[0];
String s, t;
int cch = 0;
do
cch += rg[--i].Length;
while (i > 0);
if (cch == 0)
return String.Empty;
i = rg.Length;
fixed (Char* _p = (s = new String(default(Char), cch)))
{
Char* pDst = _p + cch;
do
if ((t = rg[--i]).Length > 0)
fixed (Char* pSrc = t)
memcpy(pDst -= t.Length, pSrc, (UIntPtr)(t.Length << 1));
while (pDst > _p);
}
return s;
}
[DllImport("MSVCR120_CLR0400", CallingConvention = CallingConvention.Cdecl)]
static extern unsafe void* memcpy(void* dest, void* src, UIntPtr cb);
Я должен отметить, что этот код имеет небольшие изменения по сравнению с тем, что я использую сам. В оригинале, я называю cpblk IL инструкции от C # для фактического копирования. Для простоты и переносимости в коде я заменил это на P / Invoke memcpy
, как вы можете видеть. Для достижения максимальной производительности на 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 явно запрашивает «самый эффективный» метод, результат предполагает, что мой ответ применим. Если это решит ваши проблемы, я приглашаю вас пересмотреть свое отрицательное мнение. Другое решение:
внутри цикла используйте список вместо строки.
List<string> lst= new List<string>();
for(int i=0; i<100000; i++){
...........
lst.Add(...);
}
return String.Join("", lst.ToArray());;
это очень очень быстро
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
если у вас есть создать массив для него на месте.