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

c# .net string optimization

189066 просмотра

17 ответа

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

Автор: jimmij Источник Размещён: 23.07.2019 01:43

Ответы (17)


142 плюса

Решение

Этот 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 });
Автор: TheEmirOfGroofunkistan Размещён: 21.08.2008 08:30

261 плюса

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

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

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

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

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

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

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

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

Автор: Lee Размещён: 21.08.2008 08:39

73 плюса

Существует 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 .

Автор: Mr_Green Размещён: 04.09.2012 06:15

52 плюса

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

Эмпирические правила

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

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

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

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

Автор: palehorse Размещён: 21.08.2008 08:34

11 плюса

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

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

Автор: Adam V Размещён: 21.08.2008 08:35

8 плюса

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

Автор: Glenn Slayden Размещён: 10.11.2017 10:06

6 плюса

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

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

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

Автор: JohnIdol Размещён: 02.10.2008 07:19

5 плюса

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

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

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

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

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

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

Автор: DBN Размещён: 31.10.2014 05:30

4 плюса

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

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

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

Автор: talles Размещён: 14.10.2013 05:15

3 плюса

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

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

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

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

Автор: RP Nainwal Размещён: 28.03.2017 12:32

2 плюса

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

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

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

Автор: TheSmurf Размещён: 21.08.2008 08:28

2 плюса

Попробуйте это 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-й код закончится очень быстро, и память будет в хорошем количестве.

Второй код, возможно, память будет в порядке, но это займет больше времени ... намного дольше. Так что, если у вас есть приложение для большого количества пользователей и вам нужна скорость, используйте 1-й. Если у вас есть приложение для краткосрочного однопользовательского приложения, возможно, вы можете использовать оба, или второе будет более «естественным» для разработчиков.

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

Автор: Eduardo Mass Размещён: 01.01.2016 05:25

1 плюс

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

Автор: Dhibi_Mohanned Размещён: 24.04.2014 10:27

1 плюс

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

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

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

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

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

Автор: asady Размещён: 19.01.2018 12:19

1 плюс

Это действительно зависит от вашей модели использования. Подробный тест между string.Join, string, Concat и string.Format можно найти здесь: String.Format не подходит для интенсивной регистрации

(Это на самом деле тот же ответ, который я дал на этот вопрос)

Автор: Liran Размещён: 31.05.2011 06:56

0 плюса

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

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

Автор: Nick Размещён: 21.08.2008 08:31

0 плюса

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

Автор: Jon Dewees Размещён: 21.08.2008 08:34
32x32