В какой момент использование StringBuilder становится незначительным или накладным?

StackOverflow https://stackoverflow.com/questions/550702

  •  23-08-2019
  •  | 
  •  

Вопрос

Недавно я обнаружил, что использую StringBuilder для всех конкатенаций строк, больших и малых, однако в недавнем тесте производительности я заменил stringout = string1 + "." строка2 конкатенация стилей (используется в цикле 10000x + с обновлением StringBuilder каждый раз) для StringBuilder, просто чтобы посмотреть, какую разницу это будет иметь при незначительной конкатенации.

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

В какой момент «обновление» объекта StringBuilder сводит на нет преимущества его использования?

Это было полезно?

Решение

Правило, которому я следую -

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

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

string s = String.Empty;
for (int i = 0; i < 10000; ++i)
{
    s += "A";
}

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

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

Я уверен, что у меня есть еще один ответ, где я разместил всего лишь ссылка на мою статью а затем его краткое изложение, но здесь мы идем снова.

  • Обязательно используйте StringBuilder когда вы объединяете в нетривиальный цикл, особенно если вы точно не знаете (во время компиляции), сколько итераций вы сделаете в цикле.Например, чтение файла посимвольно и построение строки по ходу действия с помощью оператора += потенциально может привести к самоубийству производительности.

  • Обязательно используйте оператор конкатенации, когда вы можете (читабельно) указать все, что необходимо объединить, в одном операторе.(Если вам нужно объединить массив объектов, рассмотрите возможность вызова String.Concat явно - или String.Join если вам нужен разделитель.)

  • Не бойтесь разбивать литералы на несколько связанных битов — результат будет тот же.Вы можете улучшить читаемость, например, разбив длинный литерал на несколько строк, без ущерба для производительности.

  • Если вам нужны промежуточные результаты конкатенации для чего-то другого, кроме подачи следующей итерации конкатенации, StringBuilder тебе не поможет.Например, если вы создадите полное имя из имени и фамилии, а затем добавите в конец третью часть информации (возможно, псевдоним), вы получите только пользу от использования StringBuilder если вам не нужна строка (имя + фамилия) для других целей (как в примере, который создает Person объект).

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

Иногда стоит посмотреть документация:

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

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

stringOut = ...
for(...)
    stringOut += "."
    stringOut += string2

Мое эмпирическое правило простое.

  1. Если вы разумно можете написать одно выражение, которое выдает окончательный результат, используйте +.
  2. Если вы не можете (из-за размера или изменчивости), используйте StringBuilder.

По моему опыту, такие выражения, как:

"Id: " + item.id + " name: " + item.name

можно написать и понять гораздо проще, чем:

StringBuilder sb = new StringBuilder();
sb.append("Id: ").append(item.id);
sb.append(" name: ").append(item.name);

(с последующим использованием строки из sb там, где было бы написано приведенное выше выражение), и оно работает одинаково хорошо (подсказка:посмотрите на скомпилированный код, чтобы понять, почему!)

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

String s = somethingExpression;
...
s += someOtherExpression;
...
s += yetAnotherExpression;
...

От MSDN:

T] HE String Class предпочтительнее для операции конкатенации, если фиксированное количество строковых объектов объединяется.В этом случае индивидуальные операции конкатенации могут быть даже объединены в одну операцию компилятором.Объект StringBuilder предпочтительнее для операции конкатенации, если целостное количество строк сочетается;Например, если цикл объединяет случайное количество строк пользовательского ввода.

Я думаю, ответ «это зависит» - если вы объединяете внутри цикла более нескольких итераций, то StringBuilder почти всегда обеспечит лучшую производительность, но единственный способ узнать наверняка - это фактически профилировать.

На эту тему есть интересная статья Кодирование ужасов.Джефф получил следующие результаты для 100 000 итераций на двухъядерном процессоре Core 2 Duo с тактовой частотой 3,5 ГГц:

 Simple Concatenation    - 606 ms
 String.Format           - 665 ms
 string.Concat           - 587 ms
 String.Replace          - 979 ms
 StringBuilder           - 588 ms

От Точка Чистая Перлз:

Когда использовать StringBuilder?

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

Иногда можно использовать небольшие циклы из 4 или меньше итераций с простыми строковыми конкатами.Однако в крайних случаях это может иметь катастрофические последствия.Планируйте свои крайние случаи с помощью StringBuilder.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top