Самый эффективный способ объединения строк? - PullRequest
255 голосов
/ 22 августа 2008

Какой самый эффективный способ объединения строк?

Ответы [ 17 ]

258 голосов
/ 22 августа 2008

Рико Мариани , гуру .NET Performance, опубликовал статью на эту тему. Это не так просто, как можно подозревать. Основной совет таков:

Если ваш шаблон выглядит так:

x = f1(...) + f2(...) + f3(...) + f4(...)

это один конкат, и он быстрый, StringBuilder, вероятно, не поможет.

Если ваш шаблон выглядит так:

if (...) x += f1(...)
if (...) x += f2(...)
if (...) x += f3(...)
if (...) x += f4(...)

тогда вы, вероятно, хотите StringBuilder.

Еще одна статья в поддержку этого утверждения написана Эриком Липпертом, в котором он подробно описывает оптимизацию, выполненную в одной строке + конкатенации.

139 голосов
/ 22 августа 2008

Метод StringBuilder.Append() намного лучше, чем использование оператора +. Но я обнаружил, что при выполнении 1000 конкатенаций или менее String.Join() даже более эффективен, чем StringBuilder.

StringBuilder sb = new StringBuilder();
sb.Append(someString);

Единственная проблема с String.Join заключается в том, что вам нужно объединить строки с общим разделителем. (Отредактируйте :), как указал @ryanversaw, вы можете сделать строку-разделитель. Пусто.

string key = String.Join("_", new String[] 
{ "Customers_Contacts", customerID, database, SessionID });
70 голосов
/ 04 сентября 2012

Существует 6 типов конкатенации строк:

  1. Использование символа плюс (+).
  2. Использование string.Concat().
  3. Использование string.Join().
  4. Использование string.Format().
  5. Использование string.Append().
  6. Использование StringBuilder.

В эксперименте было доказано, что string.Concat() - лучший способ приблизиться, если слова меньше 1000 (приблизительно) и если слова больше 1000, тогда следует использовать StringBuilder.

Для получения дополнительной информации зайдите на этот сайт .

string.Join () против string.Concat ()

Метод string.Concat здесь эквивалентен вызову метода string.Join с пустым разделителем. Добавление пустой строки выполняется быстро, но не выполняется даже быстрее, поэтому здесь лучше использовать метод string.Concat .

51 голосов
/ 22 августа 2008

С Чин До - StringBuilder не всегда быстрее :

Правила большого пальца

  • При объединении трех динамических строковых значений или менее используйте традиционное объединение строк.

  • При объединении более трех динамических строковых значений используйте StringBuilder.

  • При построении большой строки из нескольких строковых литералов используйте либо литерал @ string, либо оператор inline +.

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

11 голосов
/ 22 августа 2008

Если вы работаете в цикле, StringBuilder, вероятно, является подходящим способом; это избавляет вас от необходимости регулярно создавать новые строки. В коде, который будет запускаться только один раз, String.Concat, вероятно, подойдет.

Однако Рико Мариани (гуру оптимизации .NET) составил тест , в котором он в конце заявил, что в большинстве случаев он рекомендует String.Format.

7 голосов
/ 11 ноября 2017

Вот самый быстрый метод, который я развил за десятилетие для моего крупномасштабного приложения НЛП. У меня есть варианты для 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 .

6 голосов
/ 02 октября 2008

Из этой статьи MSDN :

Есть некоторые накладные расходы, связанные с создание объекта StringBuilder, оба во времени и памяти. На машине с быстрая память, StringBuilder становится стоит, если вы делаете около пяти операции. Как правило, я сказал бы 10 или более строковых операций является оправданием накладных расходов на любая машина, даже более медленная.

Так что, если вы доверяете MSDN, используйте StringBuilder, если вам нужно выполнить более 10 операций / конкатенаций строк - в противном случае можно использовать простой конкатнат строк с '+'.

5 голосов
/ 31 октября 2014

Добавляя к другим ответам, имейте в виду, что StringBuilder можно указать начальный объем памяти для выделения .

Параметр acity определяет максимальное количество символов, которое может быть сохранено в памяти, выделенной текущим экземпляром. Его значение присваивается свойству Capacity . Если количество символов, которые будут сохранены в текущем экземпляре, превышает это значение Вместимость , объект StringBuilder выделяет дополнительную память для их хранения.

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

Повторное добавление в StringBuilder, который не был предварительно выделен, может привести к большому количеству ненужных выделений, как многократное объединение обычных строк.

Если вы знаете, какова будет длина последней строки, можете легко ее вычислить или можете сделать обоснованное предположение об общем случае (выделение слишком большого объема не обязательно является плохой вещью), вам следует предоставить эту информацию конструктор или свойство Capacity . Особенно при выполнении тестов производительности для сравнения StringBuilder с другими методами, такими как String.Concat, которые делают то же самое внутри. Любой тест, который вы видите в сети и который не включает предварительное распределение StringBuilder в свои сравнения, неверен.

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

4 голосов
/ 14 октября 2013

Также важно указать, что вы должны использовать оператор +, если объединяете строковые литералы .

Когда вы объединяете строковые литералы или строковые константы с помощью оператора +, компилятор создает одну строку. Конкатенация во время выполнения не происходит.

Как: объединить несколько строк (Руководство по программированию в C #)

3 голосов
/ 28 марта 2017

Ниже приводится еще одно альтернативное решение для объединения нескольких строк.

String str1 = "sometext";
string str2 = "some other text";

string afterConcate = $"{str1}{str2}";

интерполяция строк

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...