Самый эффективный способ конкатенации строк?

Каков наиболее эффективный способ конкатенации строк?

Ответ 1

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

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

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

string key = String.Join("_", new String[] 
{ "Customers_Contacts", customerID, database, SessionID });

Ответ 2

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

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

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

что один concat и это zippy, StringBuilder, вероятно, не поможет.

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

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

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

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

Ответ 3

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

  • Использование символа плюса (+).
  • Использование string.Concat().
  • Использование string.Join().
  • Использование string.Format().
  • Использование string.Append().
  • Использование StringBuilder.

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

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

string.Join() vs string.Concat()

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

Ответ 4

Из Chinh Do - StringBuilder не всегда быстрее:

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

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

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

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

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

Ответ 5

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

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

Ответ 6

Вот самый быстрый метод, который я развил за десятилетие для моего крупномасштабного приложения НЛП. У меня есть варианты для IEnumerable<T> и других типов ввода, с и без разделителей разных типов (Char, String), но здесь я показываю простой случай объединения всех строк в массиве в одну строку без разделителя. Последняя версия здесь разработана и протестирована на С# 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 из С# для фактического копирования. Для простоты и переносимости в этом коде я заменил его на P/Invoke memcpy, как вы можете видеть. Для максимальной производительности на x64 (но, возможно, не на x86) вы можете использовать вместо этого метод cpblk.

Ответ 7

Из этого статья MSDN:

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

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

Ответ 8

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

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

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

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

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

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

Ответ 9

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

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

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

Ответ 10

Следующее может быть еще одним альтернативным решением для конкатенации нескольких строк.

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

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

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

Ответ 11

Наиболее эффективным является использование StringBuilder, например:

StringBuilder sb = new StringBuilder();
sb.Append("string1");
sb.Append("string2");
...etc...
String strResult = sb.ToString();

@jonezy: String.Concat в порядке, если у вас есть несколько мелких вещей. Но если вы соедините мегабайты данных, ваша программа, скорее всего, будет танком.

Ответ 12

Попробуйте два кода, и вы найдете решение.

 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-й. Если у вас есть приложение для краткосрочного однопользовательского приложения, возможно, вы можете использовать оба, или 2-й будет более "естественным" для разработчиков.

Приветствия.

Ответ 14

System.String неизменен. Когда мы изменяем значение строковой переменной, новая память распределяется на новое значение и освобождается выделение предыдущей памяти. System.StringBuilder был разработан так, чтобы иметь концепцию изменяемой строки, где могут выполняться различные операции без выделения отдельной ячейки памяти для модифицированной строки.

Ответ 15

Другое решение:

внутри цикла, используйте List вместо строки.

List<string> lst= new List<string>();

for(int i=0; i<100000; i++){
    ...........
    lst.Add(...);
}
return String.Join("", lst.ToArray());;

это очень быстро.

Ответ 16

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

Итак, для более 2-3 строк используйте код DannySmurf. В противном случае просто используйте оператор +.

Ответ 17

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