Update: Мои тесты были неправильные. StringBuilder выигрывает даже при объединении 5 строк
Я сравнил производительность StringBuilder и String.Concat c разным количеством строк, учитывая время на создание объекта StringBuilder.
При объединении 5 строк String.Concat всегда быстрее, иногда в 10 раз
При объедении 10 строк String.Concat всегда быстрее, иногда в 10 раз
При объединении 20 строк String.Concat всегда быстрее, иногда в 10 раз
Если ли смысл использовать StringBuilder для объединения маленького количества строк? Вроде объект StringBuilder сам по себе отнимает больше ресурсов, чем 20 строк.
Код, который использовался для теста:
class Program
{
static void Main(string[] args)
{
const int countOfStrings = 20;
string[] stringsToMerge = new string[countOfStrings];
for (int i = 0; i < countOfStrings; i++)
{
stringsToMerge[i] = "stringN" + i;
}
Console.WriteLine("Count of strings:" + countOfStrings);
Stopwatch stopWatch = new Stopwatch();
TimeSpan ts;
stopWatch.Start();
stopWatch.Stop();
stopWatch.Restart();
string s = stringsToMerge[0];
for (int i = 1; i < countOfStrings; i++)
{
s = string.Concat(s, stringsToMerge[i]);
}
stopWatch.Stop();
ts = stopWatch.Elapsed;
Console.WriteLine("String.Concat ms:" + ts.TotalMilliseconds);
stopWatch.Restart();
StringBuilder stringBuilder = new StringBuilder(stringsToMerge[0]);
for (int i = 1; i < countOfStrings; i++)
{
stringBuilder.Append(stringsToMerge[i]);
}
stopWatch.Stop();
ts = stopWatch.Elapsed;
Console.WriteLine("StringBuilder ms:" + ts.TotalMilliseconds);
Console.ReadKey();
}
}
Я исправил ваш код. Во-первых, перед тестированием скорости, все методы нужно "прогреть". При первом вызове JIT-компилятор генерирует машинный код с IL и это занимает некоторое время. Во-вторых, не нужно тестировать одну итерацию, так как случайное событие в ОС может исказить результат. Во-третьих, вы передаете странное значение, в конструктор StringBuilder
. При его использовании заведомо создается маленький размер буфера, который будет расширяться несколько раз. Для максимальной производительности, если есть возможность, вы должны задавать размер буфера, который не будет менятся.
И не забывайте запускать в Release
, а не в Debug
.
В исправленном варианте (не трогал конструктор):
Count of strings:5
String.Concat ms:1097.4772
StringBuilder ms:1294.881
Count of strings:10
String.Concat ms:2848.4845
StringBuilder ms:1970.4477
Уже на 10 выигрывает StringBuilder
.
const int countOfStrings = 5;
const int iterations = 10000000;
string[] stringsToMerge = new string[countOfStrings];
for (int i = 0; i < countOfStrings; i++)
{
stringsToMerge[i] = "stringN" + i;
}
// компилируем IL в машинный код
string.Concat("123", "qwe");
var x = new StringBuilder(40);
x.Append("123qwe");
Console.WriteLine("Count of strings:" + countOfStrings);
Stopwatch stopWatch = new Stopwatch();
TimeSpan ts;
stopWatch.Start();
stopWatch.Stop();
stopWatch.Restart();
for (int iter = 0; iter < iterations; iter++)
{
string s = stringsToMerge[0];
for (int i = 1; i < countOfStrings; i++)
{
s = string.Concat(s, stringsToMerge[i]);
}
}
stopWatch.Stop();
ts = stopWatch.Elapsed;
Console.WriteLine("String.Concat ms:" + ts.TotalMilliseconds);
stopWatch.Restart();
for (int iter = 0; iter < iterations; iter++)
{
StringBuilder stringBuilder = new StringBuilder(stringsToMerge[0]);
for (int i = 1; i < countOfStrings; i++)
{
stringBuilder.Append(stringsToMerge[i]);
}
}
stopWatch.Stop();
ts = stopWatch.Elapsed;
Console.WriteLine("StringBuilder ms:" + ts.TotalMilliseconds);
Если же я переделаю использование StringBuilder
, то он выигрывает уже на 5 строках:
StringBuilder stringBuilder = new StringBuilder(100);
for (int i = 0; i < countOfStrings; i++)
{
stringBuilder.Append(stringsToMerge[i]);
}
Count of strings:5
String.Concat ms:1053.0082
StringBuilder ms:699.7725
Даже если не принимать во внимание неправильность тестов - пусть вы провели более тщательное тестирование и выяснили, например, что на 10 строках результат следующий
Count of strings:10
String.Concat ms:2848.4845
StringBuilder ms:1970.4477
Какой вывод вы из этого делаете?
StringBuilder выигрывает даже при объединении 5 строк
Какой реальный вывод стоит сделать из таких результатов?
Нет ощутимой разницы между StringBuilder и String.Concat в случаях, если ваша программа не занимается исключительно сложением миллиардов строк. Во всех остальных случаях вы не заметите разницы. Потому что разница на одной операции - 0.00000009 секунд.
Более того, если разница между StringBuilder и String.Concat на одном сложении для вас значительна - значит вы выбрали неправильную платформу и неправильный язык. Пишите на чем-нибудь более низкоуровневом, что даст вам максимальную производительность.
Вы преследуете неправильную цель.
Не стоит заниматься микрооптимизациями, компилятор делает это сейчас или будет делать в будущем лучше.
Например, string.Concat
имеет больше информации о том, что именно вы хотите сделать, поэтому он может быть как минимум настолько же быстрым, как и использование StringBuilder
'а в цикле. Если он сейчас, на вашей платформе, на вашей версии JIT-компилятора медленнее, это ничего не значит, и может измениться в близком будущем. Вот, например, (неполный) список улучшений производительности, введённых недавно в .NET Core 2:
Queue<>.Enqueue
и Dequeue
ускорено вдвоеSortedSet<>
ускорен в 600 разList<>.Add
ускорен в 1.3 разаConcurrentQueue<>
ускорена в 3.5 разаstring.StartsWith
ускорено вдвоеи так далее.
Таким образом, измерения мелкой производительности BCL релевантны только на той версии библиотеки и в тот момент, когда вы их проводите.
Оптимизируйте лучше алгоритмы. Прирост производительности на этом будет гораздо больше, чем выцеживание наносекунд из базовых структур данных.
Я хотел сделать заметку хочу сказать о памяти (этот вопрос Вообще задаются в экзамене 70-483 Programming in C#).
'string' (immutable) является неизменен, непреложный означает, что если вы создаете строковый объект, то вы не можете его изменить и всегда создаете новый объект типа 'string' в памяти.
'StringBuilder' (mutable) является измени мой (То есть он не создает новый объект), означает что если вы создаете объект 'StringBuilder', вы можете выполнять любую операцию, например вставку, замену или добавление, без создания нового экземпляра для каждый раз. он обновит строку в одном месте в памяти, не создаст новое пространство в памяти.
То есть 'string.Concat()' он создаёт каждый раз новый объект 'string'. это влияет на память потому что 'string' (immutable) является неизменен!
Оборудование для ресторана: новинки профессиональной кухонной техники
Частный дом престарелых в Киеве: комфорт, забота и профессиональный уход
ЗдравствуйтеПытаюсь понять взаимодействие метода с# и функции js скрипта
Я пытаюсь подключить свой довольно большой json-файл и вывести из него информацию в react, но получаю ошибкуmap is not a function