Я понимаю преимущества StringBuilder.
Но если я хочу объединить две строки, я предполагаю, что лучше (быстрее) сделать это без StringBuilder. Это верно?
В какой момент (количество строк) лучше использовать StringBuilder?
c#
stringbuilder
Шираз Бхайджи
источник
источник
Ответы:
Я настоятельно рекомендую вам прочитать «Печальная трагедия театра микрооптимизации» Джеффа Этвуда.
Он рассматривает простую конкатенацию, StringBuilder и другие методы.
Теперь, если вы хотите увидеть какие-то числа и графики, перейдите по ссылке;)
источник
Это действительно так, вы можете найти, почему именно очень хорошо объяснено на:
http://www.yoda.arachsys.com/csharp/stringbuilder.html
Подводя итог: если вы можете объединить строки за один раз, как
var result = a + " " + b + " " + c + ..
вам лучше без StringBuilder, поскольку делается только копия (длина результирующей строки рассчитывается заранее);
Для структуры типа
var result = a; result += " "; result += b; result += " "; result += c; ..
новые объекты создаются каждый раз, поэтому вам следует рассмотреть StringBuilder.
В конце статьи резюмируются эти практические правила:
источник
System.String - неизменяемый объект - это означает, что всякий раз, когда вы изменяете его содержимое, он выделяет новую строку, а это требует времени (и памяти?). Используя StringBuilder, вы изменяете фактическое содержимое объекта без выделения нового.
Поэтому используйте StringBuilder, когда вам нужно сделать много изменений в строке.
источник
Не совсем ... вам следует использовать StringBuilder, если вы объединяете большие строки или у вас много конкатенаций, например, в цикле.
источник
StringBuilder
только если цикл или конкатенация являются проблемой производительности для спецификаций.string s = "abcd"
, по крайней мере, это последнее Я слышал ... правда, с переменными, скорее всего, Concat.a + "hello" + "somethingelse"
и мне никогда не приходилось об этом беспокоиться. Если это станет проблемой, я воспользуюсь StringBuilder. Но я не беспокоился об этом в первую очередь и тратил меньше времени на его написание.Вот простое тестовое приложение, чтобы доказать это:
class Program { static void Main(string[] args) { const int testLength = 30000; var StartTime = DateTime.Now; //TEST 1 - String StartTime = DateTime.Now; String tString = "test string"; for (int i = 0; i < testLength; i++) { tString += i.ToString(); } Console.WriteLine((DateTime.Now - StartTime).TotalMilliseconds.ToString()); //result: 2000 ms //TEST 2 - StringBuilder StartTime = DateTime.Now; StringBuilder tSB = new StringBuilder("test string"); for (int i = 0; i < testLength; i++) { tSB.Append(i.ToString()); } Console.WriteLine((DateTime.Now - StartTime).TotalMilliseconds.ToString()); //result: 4 ms Console.ReadLine(); } }
Полученные результаты:
30'000 итераций
1000 итераций
500 итераций
источник
Перефразировать
Обычно я использую построитель строк для любого блока кода, который приведет к объединению трех или более строк.
источник
Однозначного ответа нет, только практические правила. Мои личные правила выглядят примерно так:
StringBuilder
.StringBuilder
.Если это не так, используйте файл
StringBuilder
.источник
Да. Но, что более важно, в таких ситуациях гораздо удобнее использовать ваниль
String
. С другой стороны, использование его в цикле имеет смысл и может быть таким же читаемым, как и конкатенация.Я бы опасался практических правил, в которых в качестве порогового значения указывается конкретное число конкатенации. Использование его в циклах (и только в циклах), вероятно, так же полезно, легче запоминается и имеет больше смысла.
источник
Так как этому трудно найти объяснение, которое бы не зависело от мнений и не сопровождалось битвой гордости, я решил написать небольшой код на LINQpad, чтобы проверить это сам.
Я обнаружил, что использование строк небольшого размера вместо использования i.ToString () изменяет время отклика (видимое в небольших циклах).
В тесте используются разные последовательности итераций, чтобы измерения времени находились в разумно сопоставимых диапазонах.
Я скопирую код в конце, чтобы вы могли попробовать это сами (results.Charts ... Dump () не будет работать вне LINQPad).
Выходные данные (ось X: количество протестированных итераций, ось Y: время в тиках):
Последовательность итераций: 2, 3, 4, 5, 6, 7, 8, 9, 10
Последовательность итераций: 10, 20, 30, 40, 50, 60, 70, 80
Последовательность итераций: 100, 200, 300, 400, 500
Код (написан с использованием LINQPad 5):
void Main() { Test(2, 3, 4, 5, 6, 7, 8, 9, 10); Test(10, 20, 30, 40, 50, 60, 70, 80); Test(100, 200, 300, 400, 500); } void Test(params int[] iterationsCounts) { $"Iterations sequence: {string.Join(", ", iterationsCounts)}".Dump(); int testStringLength = 10; RandomStringGenerator.Setup(testStringLength); var sw = new System.Diagnostics.Stopwatch(); var results = new Dictionary<int, TimeSpan[]>(); // This call before starting to measure time removes initial overhead from first measurement RandomStringGenerator.GetRandomString(); foreach (var iterationsCount in iterationsCounts) { TimeSpan elapsedForString, elapsedForSb; // string sw.Restart(); var str = string.Empty; for (int i = 0; i < iterationsCount; i++) { str += RandomStringGenerator.GetRandomString(); } sw.Stop(); elapsedForString = sw.Elapsed; // string builder sw.Restart(); var sb = new StringBuilder(string.Empty); for (int i = 0; i < iterationsCount; i++) { sb.Append(RandomStringGenerator.GetRandomString()); } sw.Stop(); elapsedForSb = sw.Elapsed; results.Add(iterationsCount, new TimeSpan[] { elapsedForString, elapsedForSb }); } // Results results.Chart(r => r.Key) .AddYSeries(r => r.Value[0].Ticks, LINQPad.Util.SeriesType.Line, "String") .AddYSeries(r => r.Value[1].Ticks, LINQPad.Util.SeriesType.Line, "String Builder") .DumpInline(); } static class RandomStringGenerator { static Random r; static string[] strings; public static void Setup(int testStringLength) { r = new Random(DateTime.Now.Millisecond); strings = new string[10]; for (int i = 0; i < strings.Length; i++) { strings[i] = Guid.NewGuid().ToString().Substring(0, testStringLength); } } public static string GetRandomString() { var indx = r.Next(0, strings.Length); return strings[indx]; } }
источник
Пока вы можете физически набрать количество конкатенаций (a + b + c ...), это не должно иметь большого значения. N в квадрате (при N = 10) - это 100-кратное замедление, что не должно быть так уж плохо.
Большая проблема - когда вы объединяете сотни строк. При N = 100 вы получаете замедление в 10000 раз. Что очень плохо.
источник
Я не думаю, что есть тонкая грань между тем, когда использовать, а когда нет. Если, конечно, кто-то не выполнил какие-то обширные испытания, чтобы выйти с золотыми условиями.
Для меня я не буду использовать StringBuilder, если просто объединю две огромные строки. Если есть цикл с неопределенным счетчиком, я, скорее всего, это сделаю, даже если цикл может быть небольшим.
источник
Однократное объединение не стоит использовать StringBuilder. Как правило, я использовал 5 конкатенаций.
источник