String против StringBuilder

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

В программе, над которой я работаю, много добавлений строк, управляемых регистром (более 500). StringBuilder - лучший выбор?

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
220
0
205 813
24
Перейти к ответу Данный вопрос помечен как решенный

Ответы 24

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

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

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

Ответ принят как подходящий

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

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

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

Хорошее практическое правило - использовать String, если вы не собираетесь его менять, и StringBuilder, если вы собираетесь его менять.

Tim 16.09.2008 21:23

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

Scott Lawrence 16.09.2008 22:18

Outlaw: я думаю, что это должно стать отдельным ответом, за который голосуют отдельно, если я правильно понимаю StackOverflow.

Jay Bazuzi 17.09.2008 09:47

на основе моего опыта, если вы пытаетесь объединить около 10-15 строк, вы можете использовать строку, но если нет. строк больше, тогда используйте построитель строк

Peeyush 01.03.2012 10:38

Это все еще зависит от того, как его использовать, для ссылки на тесты, которые мне нравятся Coding Horror - Печальная трагедия театра микрооптимизации

Erik Philips 27.07.2013 21:38

Если String Builder настолько мощный, то почему у нас есть String. Почему бы нам не уничтожить полностью String. Я задал этот вопрос, чтобы вы могли сказать мне ПРЕИМУЩЕСТВО String над StringBuilder

Unbreakable 24.05.2018 21:56

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

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

Алекс

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

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

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

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

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

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

Хорошая статья, связанная с производительностью, здесь

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

например.

StringBuilder sb = новый StringBuilder (50);

Не уверен, что вы понимаете, что означает неизменный. Строки неизменяемы, их НЕЛЬЗЯ изменить. Все, что «изменилось», на самом деле просто означает, что старое значение остается в куче без ЛЮБОГО указателя на его местонахождение. StringBuilder (изменяемый) - это ссылочный тип кучи, указатель на кучу изменен и выделение пространства для этого изменения.

Tom Stickel 10.06.2014 02:32

Чтобы прояснить, что Джиллиан сказала о 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();

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

CodesInChaos 28.07.2013 00:23

@CodesInChaos, неизменяемая строковая переменная, специально назначается в конце каждой строки, разве это не создает обязательство по созданию строки? Однако я согласен с тем, что нет причин обрабатывать каждую отдельную строку по-разному (и я не уверен, что это так), хотя потеря производительности происходит из-за перераспределения, поэтому это не имеет значения.

Saeb Amini 22.01.2015 15:11

@SaebAmini - если a является локальной переменной, а объект, на который он ссылается, не был назначен какой-либо другой переменной (которая может быть доступна другому потоку), хороший оптимизатор может определить, что a не используется любым другим кодом во время этой последовательности строк ; имеет значение только значение окончательныйa. Таким образом, он мог обрабатывать эти три строки кода, как если бы они были написаны a = b + c + d;.

ToolmakerSteve 15.11.2018 16:01

Этот тест показывает, что обычная конкатенация выполняется быстрее при объединении 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 () добавляет строку к пустому пространству в конце массива символов; если массив слишком мал, он создает новый массив большего размера и копирует туда буфер. Итак, в приведенном выше примере StringBuilder может потребоваться только один массив, содержащий все 5 добавлений к строке - в зависимости от размера его буфера. Вы можете указать StringBuilder, насколько большим должен быть его буфер в конструкторе.

Незначительный нюанс: немного странно сказать «мы создали 13 строковых объектов, и 12 из них оказались бесполезными», а затем сказать, что StringBuilder устраняет эту проблему. В конце концов, шесть строк у вас нет другого выбора, кроме как создать; они из i.ToString(). Таким образом, с StringBuilder вам все равно придется создавать строки 6 + 1; он сократил создание 13 струн до создания 7 струн. Но это все еще неправильный взгляд на это; создание шести числовых строк не имеет значения. Итог: вам просто не следовало упоминать шесть струн, созданных i.ToString(); они не являются частью сравнения эффективности.

ToolmakerSteve 15.11.2018 16:17

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

var sb = new StringBuilder(int capacity);

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

Нет необходимости вызывать EnsureCapacity сразу после создания экземпляра StringBuilder. Просто создайте экземпляр StringBuilder следующим образом: var sb = new StringBuilder(int capacity).

David Ferenczy Rogožan 16.03.2016 20:16

Мне сказали, что полезно использовать простое число.

Karl Gjertsen 09.05.2016 11:46

StringBuilder предпочтительнее ЕСЛИ, вы выполняете несколько циклов или вилок в проходе кода ... однако для производительности PURE, если вы можете уйти с объявлением строки ОДИН, это намного более производительно.

Например:

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 внутри (если есть сомнения ... проверьте отражатель!)

Я бы хотел, чтобы вы сказали, как вы это знаете / как это проверить.

ChrisW 17.07.2009 05:39

Вы не проверяете производительность в отражателе: вы проверяете производительность по времени выпуска кода, анализируете с помощью профилировщика и ищете объяснения с помощью отражателя.

Albin Sunnanbo 26.10.2010 10:24

Рассмотрите возможность использования String.Format () для объединения небольшого количества небольших строк, особенно если целью является форматирование сообщений для отображения пользователю.

Gary Kindel 18.12.2010 18:39

Это очень плохая информация. («строка myString более эффективна») совсем не соответствует действительности.

Tom Stickel 04.04.2013 08:03

Информация в этом ответе неверна. StringBuilder немного быстрее, чем конкатенация в том же операторе; однако вы заметите разницу между ними, только если проделаете это сотни тысяч раз (Источник). Как сказано в источнике, "это просто не имеет значения!"

David Sherret 07.10.2014 21:57

Альбин Суннанбо: нет, нужно сравнить время выполнения, чтобы указать, какая программа работает быстрее. Вы можете сделать это с помощью одной математики. Предположим, мы знаем стоимость C каждой постоянной операции. Затем вы можете сформулировать стоимость в виде математического выражения. Даже если вам неизвестна конкретная стоимость операций, но вы можете сказать, что операция x занимает больше (или больше или равное количество) времени, чем операция y, мы можем сформулировать оптимальное решение.

kam 18.02.2020 01:02

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

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

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

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

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

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

The performance of a concatenation operation for a String or StringBuilder object depends on how often a memory allocation occurs. A String concatenation operation always allocates memory, whereas a StringBuilder concatenation operation only allocates memory if the StringBuilder object buffer is too small to accommodate the new data. Consequently, the String class is preferable for a concatenation operation if a fixed number of String objects are concatenated. In that case, the individual concatenation operations might even be combined into a single operation by the compiler. A StringBuilder object is preferable for a concatenation operation if an arbitrary number of strings are concatenated; for example, if a loop concatenates a random number of strings of user input.

Источник: MSDN

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

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

Как видите, 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();

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

Beginning String + at 28/01/2013 16:55:40.

Finished String + at 28/01/2013 16:55:40.

Beginning String + at 28/01/2013 16:55:40.

Finished String + at 28/01/2013 16:56:02.

Beginning Sb append at 28/01/2013 16:56:02.

Finished Sb append at 28/01/2013 16:56:02.

Если String Builder настолько мощный, то почему у нас есть String. Почему бы нам не уничтожить полностью String. Я задал этот вопрос, чтобы вы могли сказать мне ПРЕИМУЩЕСТВО String над StringBuilder

Unbreakable 24.05.2018 21:55

Безопасность потоков, сокращение памяти и функциональность (как в функциональном программировании)

feyd 10.11.2020 18:08

Простой пример, демонстрирующий разницу в скорости при использовании конкатенации String и 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 concatenation: " + time.ElapsedMilliseconds + " milliseconds");

Результат:

Using String concatenation: 15423 milliseconds

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");

Результат:

Using StringBuilder: 10 milliseconds

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

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

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

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

  • String

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

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

Strongly recommend dotnet mob article : String Vs StringBuilder in C#.

Related Stack Overflow question: Mutability of string when string doesn't change in C#?.

Строка против построителя строк:

Первым делом вы должны знать, в какой сборке живут эти два класса?

Так,

нить присутствует в пространстве имен System.

и

StringBuilder присутствует в пространстве имен System.Text.

Для объявления нить:

Вы должны включить пространство имен System. что-то вроде этого. Using System;

и

Для объявления StringBuilder:

Вы должны включить пространство имен System.text. что-то вроде этого. Using System.text;

Теперь переходим к собственному вопросу.

В чем разница между нить и StringBuilder?

Основное различие между ними заключается в том, что:

нить неизменен.

и

StringBuilder изменчив.

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

Мутабельный:: означает возможность изменения.

Неизменный:: означает Не подлежит изменению.

Например:

using System;

namespace StringVsStrigBuilder
{
    class Program
    {
        static void Main(string[] args)
        {
            // String Example

            string name = "Rehan";
            name = name + "Shah";
            name = name + "RS";
            name = name + "---";
            name = name + "I love to write programs.";

            // Now when I run this program this output will be look like this.
            // output : "Rehan Shah RS --- I love to write programs."
        }
    }
}

В этом случае мы собираемся менять один и тот же объект 5 раз.

Итак, очевидный вопрос! Что на самом деле происходит под капотом, когда мы меняем одну и ту же строку 5 раз.

Вот что происходит, когда мы меняем одну и ту же строку 5 раз.

давай посмотрим на рисунок.

Объяснение:

Когда мы впервые инициализируем эту переменную "name" как "Rehan" i-e string name = "Rehan" эта переменная создается в стеке «name» и указывает на это значение «Rehan». после выполнения этой строки: «name = name +« Shah ». ссылочная переменная больше не указывает на этот объект« Rehan », теперь она указывает на« Shah »и так далее.

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

Итак, когда мы объединяем переменную name, предыдущий объект остается в памяти, и создается другой новый строковый объект ...

Итак, из приведенного выше рисунка у нас есть пять объектов, четыре объекта выброшены, и они вообще не используются. Они все еще остаются в памяти и занимают определенный объем памяти. За это отвечает «Сборщик мусора», так очищающий эти ресурсы из памяти.

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

Это история строковой переменной.

Теперь посмотрим на объект StringBuilder. Например:

using System;
using System.Text;

namespace StringVsStrigBuilder
{
    class Program
    {
        static void Main(string[] args)
        {
            // StringBuilder Example

            StringBuilder name = new StringBuilder();
            name.Append("Rehan");
            name.Append("Shah");
            name.Append("RS");
            name.Append("---");
            name.Append("I love to write programs.");


            // Now when I run this program this output will be look like this.
            // output : "Rehan Shah Rs --- I love to write programs."
        }
    }
}

В этом случае мы собираемся менять один и тот же объект 5 раз.

Итак, очевидный вопрос! Что на самом деле происходит под капотом, когда мы меняем один и тот же StringBuilder 5 раз.

Вот что происходит, когда мы меняем один и тот же StringBuilder 5 раз.

давай посмотрим на рисунок.

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

У вас не так много мусорных объектов или non_referenced объектов stringBuilder, потому что это может быть изменено. Это изменчиво, что означает, что оно меняется со временем?

Отличия:

  • Строка присутствует в пространстве имен System, где присутствует Stringbuilder в пространстве имен System.Text.
  • строка является неизменной, а StringBuilder - изменчивой.

Другие вопросы по теме