Строка против StringBuilder

Я понимаю разницу между String и StringBuilder ( StringBuilder является изменяемым), но есть ли большая разница в производительности между этими двумя?

Программа, над которой я работаю, содержит множество приложенных аргументов строки (500+). Использует ли StringBuilder лучший выбор?

Да, разница в производительности значительна. См. Статью KB « Как улучшить производительность конкатенации строк в Visual C # ».

Вначале я всегда старался сделать код для ясности, а затем оптимизирован для производительности позже. Это намного проще, чем делать это наоборот! Однако, увидев огромную разницу в производительности в моих приложениях между этими двумя, я теперь думаю об этом немного более тщательно.

К счастью, довольно просто провести анализ производительности вашего кода, чтобы узнать, где вы тратите время, а затем изменить его, чтобы использовать StringBuilder там, где это необходимо.

Чтобы уточнить, что сказала Гиллиан о 4 строках, если у вас есть что-то вроде этого:

 string a,b,c,d; a = b + c + d; 

то он будет быстрее использовать строки и оператор плюс. Это связано с тем, что (как Java, как указывает Эрик), он внутренне использует StringBuilder автоматически (на самом деле он использует примитив, который также использует StringBuilder)

Однако, если то, что вы делаете, ближе к:

 string a,b,c,d; a = a + b; a = a + c; a = a + d; 

Затем вам нужно явно использовать StringBuilder. .Net не создает автоматически StringBuilder здесь, потому что это было бы бессмысленно. В конце каждой строки «a» должна быть (неизменной) строкой, поэтому она должна была бы создавать и размещать StringBuilder в каждой строке. Для скорости вам нужно будет использовать тот же StringBuilder, пока не закончите строительство:

 string a,b,c,d; StringBuilder e = new StringBuilder(); e.Append(b); e.Append(c); e.Append(d); a = e.ToString(); 

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

Например:

 string myString = "Some stuff" + var1 + " more stuff" + var2 + " other stuff" .... etc... etc...; 

более результативна, чем

 StringBuilder sb = new StringBuilder(); sb.Append("Some Stuff"); sb.Append(var1); sb.Append(" more stuff"); sb.Append(var2); sb.Append("other stuff"); // etc.. etc.. etc.. 

В этом случае StringBuild можно считать более ремонтопригодным, но не более эффективным, чем однострочное объявление.

9 раз из 10, хотя … используйте построитель строк.

На стороне примечание: строка + var также более эффективна, чем метод string.Format (обычно), который использует StringBuilder внутри (если есть сомнения … проверьте рефлектор!)

Этот тест показывает, что регулярное конкатенация происходит быстрее при объединении 3 или менее строк.

http://www.chinhdo.com/20070224/stringbuilder-is-not-always-faster/

StringBuilder может значительно улучшить использование памяти, особенно в случае добавления 500 строк.

Рассмотрим следующий пример:

 string buffer = "The numbers are: "; for( int i = 0; i < 5; i++) { buffer += i.ToString(); } return buffer; 

Что происходит в памяти? Создаются следующие строки:

 1 - "The numbers are: " 2 - "0" 3 - "The numbers are: 0" 4 - "1" 5 - "The numbers are: 01" 6 - "2" 7 - "The numbers are: 012" 8 - "3" 9 - "The numbers are: 0123" 10 - "4" 11 - "The numbers are: 01234" 12 - "5" 13 - "The numbers are: 012345" 

Добавив эти пять чисел в конец строки, мы создали 13 строковых объектов! И 12 из них бесполезны! Вау!

StringBuilder исправляет эту проблему. Это не «изменяемая строка», как мы часто слышим ( все строки в .NET неизменяемы ). Он работает, сохраняя внутренний буфер, массив символов. Вызов Append () или AppendLine () добавляет строку в пустое пространство в конце массива char; если массив слишком мал, он создает новый, больший массив и копирует буфер там. Поэтому в приведенном выше примере StringBuilder может потребоваться только один массив, содержащий все 5 дополнений к строке - в зависимости от размера его буфера. Вы можете сказать StringBuilder, насколько велик его буфер в конструкторе.

Простой пример, демонстрирующий разницу в скорости при использовании String contactenation vs StringBuilder :

 System.Diagnostics.Stopwatch time = new Stopwatch(); string test = string.Empty; time.Start(); for (int i = 0; i < 100000; i++) { test += i; } time.Stop(); System.Console.WriteLine("Using String contactenation: " + time.ElapsedMilliseconds + " milliseconds"); 

Результат:

Использование конвейера String: 15423 миллисекунды

 StringBuilder test1 = new StringBuilder(); time.Reset(); time.Start(); for (int i = 0; i < 100000; i++) { test1.Append(i); } time.Stop(); System.Console.WriteLine("Using StringBuilder: " + time.ElapsedMilliseconds + " milliseconds"); 

Результат:

Использование StringBuilder: 10 миллисекунд

В результате первая итерация заняла 15423 мс, а вторая итерация с использованием StringBuilder заняла 10 мс.

Мне кажется, что использование StringBuilder выполняется быстрее, намного быстрее.

Не слепо идти за StringBuilder. Существуют сценарии, в которых StringBuilder не улучшает производительность.

Рико Мариани написал две проницательные записи в блоге:

http://blogs.msdn.com/ricom/archive/2003/12/02/40778.aspx

http://blogs.msdn.com/ricom/archive/2003/12/15/43628.aspx

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

String Vs Stringbuilder

  • String

    1. в пространстве имен System
    2. неизменяемый (только для чтения) экземпляр
    3. производительность ухудшается, когда происходит непрерывное изменение стоимости
    4. безопасный stream
  • StringBuilder (изменяемая строка)

    1. в пространстве имен System.Text
    2. изменяемый экземпляр
    3. показывает лучшую производительность, так как новые изменения внесены в существующий экземпляр

Настоятельно рекомендуем статью dotnet mob: String Vs StringBuilder в C # .

Связанный вопрос переполнения стека: Возможность использования строки, когда строка не изменяется в C #? ,

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

 string result = ""; for(int i = 0; i != N; ++i) { result = result + i.ToString(); // allocates a new string, then assigns it to result, which gets repeated N times } 

против

 String result; StringBuilder sb = new StringBuilder(10000); // create a buffer of 10k for(int i = 0; i != N; ++i) { sb.Append(i.ToString()); // fill the buffer, resizing if it overflows the buffer } result = sb.ToString(); // assigns once 

Производительность операции конкатенации для объекта String или StringBuilder зависит от того, как часто происходит распределение памяти. Операция конкатенации строк всегда выделяет память, тогда как операция конкатенации StringBuilder выделяет только память, если буфер объекта StringBuilder слишком мал для размещения новых данных. Следовательно, class String является предпочтительным для операции конкатенации, если фиксированное число объектов String конкатенировано. В этом случае отдельные операции конкатенации могут быть даже объединены в одну операцию компилятором. Объект StringBuilder предпочтительнее для операции конкатенации, если произвольное количество строк конкатенировано; например, если цикл объединяет случайное число строк пользовательского ввода.

Источник: MSDN

StringBuilder лучше для построения строки из многих непостоянных значений.

Если вы создаете строку из множества постоянных значений, таких как несколько строк значений в HTML или XML-документе или других fragmentах текста, вы можете уйти с просто добавлением к одной и той же строке, потому что почти все компиляторы делают «постоянное складывание» – процесс уменьшения дерева синтаксического анализа, когда у вас есть куча постоянной манипуляции (он также используется, когда вы пишете что-то вроде int minutesPerYear = 24 * 365 * 60 ). А для простых случаев с непостоянными значениями, добавленными друг к другу, компилятор .NET уменьшит ваш код до чего-то похожего на то, что делает StringBuilder .

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

Я считаю, что StringBuilder быстрее, если у вас есть более 4 строк, которые нужно добавить вместе. Кроме того, он может делать некоторые интересные вещи, такие как AppendLine.

В .NET StringBuilder все еще быстрее, чем добавляет строки. Я уверен, что в Java они просто создают StringBuffer под капотом, когда вы добавляете строки, так что на самом деле нет разницы. Я не уверен, почему они еще не сделали этого в .NET.

Рассмотрим « Печальную трагедию Театра микро-оптимизации ».

Использование строк для конкатенации может привести к сложности выполнения в порядке O(n^2) .

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

Я видел значительный прирост производительности от использования метода метода EnsureCapacity(int capacity) на экземпляре StringBuilder перед его использованием для любого хранилища строк. Обычно я называю это в строке кода после создания экземпляра. Он имеет такой же эффект, как если бы вы создавали экземпляр StringBuilder следующим образом:

 var sb = new StringBuilder(int capacity); 

Этот вызов распределяет необходимую память раньше времени, что приводит к меньшему распределению памяти во время нескольких Append() . Вы должны понять, сколько памяти вам понадобится, но для большинства приложений это не должно быть слишком сложно. Я обычно ошибаюсь на стороне слишком большой памяти (мы говорим 1к или около того).

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

ИМХО, добавив 500+ строковых записей, обязательно должен использовать StringBuilder.

String и StringBuilder на самом деле оба неизменяемы, StringBuilder имеет встроенные буферы, которые позволяют управлять его размером более эффективно. Когда StringBuilder должен resize, это когда он перераспределяется в куче. По умолчанию он имеет значение 16 символов, вы можете установить его в конструкторе.

например.

StringBuilder sb = new StringBuilder (50);

Конкатенация строк будет стоить вам больше. В Java вы можете использовать StringBuffer или StringBuilder на основе ваших потребностей. Если вам нужна синхронизированная и streamобезопасная реализация, перейдите к StringBuffer. Это будет быстрее, чем конкатенация строк.

Если вам не нужна синхронизированная или streamовая реализация, перейдите к StringBuilder. Это будет быстрее, чем String конкатенация, а также быстрее, чем StringBuffer, поскольку они не являются накладными расходами на синхронизацию.

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

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

Alex

Как правило, если мне нужно установить значение строки более одного раза или если есть какие-либо добавления к строке, тогда это должен быть построитель строк. Я видел приложения, которые я написал в прошлом, прежде чем узнавать о строковых сборщиках, у которых был огромный отпечаток памяти, который, как кажется, продолжает расти и расти. Изменение этих программ на использование построителя строк значительно сократило использование памяти. Теперь я клянусь строчным построителем.

Мой подход всегда заключался в использовании StringBuilder при конкатенации 4 или более строк ИЛИ Когда я не знаю, как могут происходить конкатенации.

Хорошая работа, связанная с этой статьей здесь

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

Ниже приведен fragment кода, чтобы привести пример производительности. Как вы можете видеть, вы действительно только начинаете видеть значительное увеличение производительности, когда попадаете в большие итерации.

Как вы можете видеть, 200 000 итераций заняли 22 секунды, в то время как 1 миллион итераций с использованием StringBuilder были почти мгновенными.

 string s = string.Empty; StringBuilder sb = new StringBuilder(); Console.WriteLine("Beginning String + at " + DateTime.Now.ToString()); for (int i = 0; i <= 50000; i++) { s = s + 'A'; } Console.WriteLine("Finished String + at " + DateTime.Now.ToString()); Console.WriteLine(); Console.WriteLine("Beginning String + at " + DateTime.Now.ToString()); for (int i = 0; i <= 200000; i++) { s = s + 'A'; } Console.WriteLine("Finished String + at " + DateTime.Now.ToString()); Console.WriteLine(); Console.WriteLine("Beginning Sb append at " + DateTime.Now.ToString()); for (int i = 0; i <= 1000000; i++) { sb.Append("A"); } Console.WriteLine("Finished Sb append at " + DateTime.Now.ToString()); Console.ReadLine(); 

Результат приведенного выше кода:

Начало String + в 28/01/2013 16:55:40.

Законченная строка + 28/01/2013 16:55:40.

Начало String + в 28/01/2013 16:55:40.

Законченная строка + 28/01/2013 16:56:02.

Начало Sb добавлено 28/01/2013 16:56:02.

Готово Sb добавлено 28/01/2013 16:56:02.

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

  • Что более эффективно i ++ или ++ i?
  • Doxygen медленный
  • Что более эффективно: System.arraycopy vs Arrays.copyOf?
  • Секундомер против использования System.DateTime.Now для событий синхронизации
  • Разница в производительности между импортом дикой карты и требуемым импортом classа
  • Производительность C ++ по сравнению с Java / C #
  • Когда использовать StringBuilder в Java
  • Является ли использование double быстрее, чем float?
  • Как я могу оптимизировать функцию ORDER BY RAND () MySQL?
  • Заменить значения в списке с помощью Python
  • Анатомия «утечки памяти»
  • Давайте будем гением компьютера.