This question has already been answered:

Update: My tests were incorrect. StringBuilder wins even with 5 strings combined

I compared the performance of StringBuilder and String.Concat with a different number of strings, given the time to create a StringBuilder object.

When concatenating 5 strings, String.Concat is always faster, sometimes 10 times. enter image description here

When 10 strings are combined, String.Concat is always faster, sometimes 10 times. enter image description here

When you combine 20 strings, String.Concat is always faster, sometimes 10 times. enter image description here

Does it make sense to use StringBuilder to combine a small number of strings? Like the StringBuilder object in itself takes more resources than 20 strings.

The code that was used for the test:

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(); } } 

Reported as a duplicate by Grundy participants, Alexey Shimansky , insolor , andreymal , сен 9 Sep '17 at 11:20 .

A similar question was asked earlier and an answer has already been received. If the answers provided are not exhaustive, please ask a new question .

  • What code gave such results? Add to the question. - Zergatul
  • @Zergatul added - mirypoko
  • one
    And when you combine 2000 lines, who is faster? - gil9red
  • @mirypoko, it also depends on the size of the input strings, for example, with these strings: stringsToMerge[i] = "stringNstringNstringNstringNstringNstringNstringNstringNstringNstringN" + i; already in quantities of 5 pcs. string does not look better than SB , and at 20 is already hopelessly lagging behind - Andrey NOP
  • @Andrew with such a string with 5 unions on my computer String.Concat is always faster anyway, with 20 sometimes faster, sometimes not, 50 to 50. - mirypoko

4 answers 4

I fixed your code. First, before testing the speed, all methods need to be “warmed up”. When first called, the JIT compiler generates machine code with IL and it takes some time. Secondly, there is no need to test one iteration, as a random event in the OS can distort the result. Third, you pass a strange value to the constructor of a StringBuilder . When using it, a small buffer size is created, which will be expanded several times. For maximum performance, if possible, you must set the size of the buffer, which will not change.

And do not forget to run in Release , not in Debug .

In the corrected version (did not touch the designer):

 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 

Already at 10 wins 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); 

If I redo the use of StringBuilder , then he wins already on 5 lines:

 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 
  • 2
    It is also worth mentioning that you need to run tests outside of Visual Studio. - VladD September
  • one
    Ctrl + F5 (Start without debugging) should be enough, or not? - Zergatul
  • @Zergatul release version launch - LLENN
  • four
    @Zergatul "wins" with a difference of 1000 ms per 10,000,000 iterations practically means "there is no difference what to use if your program does not exclusively deal with adding billions of lines" - PashaPash
  • 3
    @Grundy is not exactly a duplicate here - the question is not caused by a problem, but by unexpected comparison results (curved tests) - PashaPash

Even if you do not take into account the incorrectness of the tests - even if you conducted a more thorough testing and found out, for example, that on 10 lines the result is the following

 Count of strings:10 String.Concat ms:2848.4845 StringBuilder ms:1970.4477 

What conclusion do you make from this?

StringBuilder wins even with 5 strings combined

What is the real conclusion to make of such results?

There is no tangible difference between StringBuilder and String.Concat in cases where your program does not deal exclusively with adding billions of strings. In all other cases, you will not notice the difference. Because the difference in a single operation is 0.00000009 seconds.

Moreover, if the difference between StringBuilder and String.Concat on one addition is significant for you, then you have chosen the wrong platform and the wrong language. Write on something lower level that will give you maximum performance.

  • You are right, there is no tangible difference. But I am writing software for the device 12 years ago. If there is an opportunity to use a more productive approach, then I want to use it. It will not be worse, but I will know that I did everything I could to make the program less slow. - mirypoko
  • 2
    @mirypoko then you should test the performance on this device, and not on the developer machine :) JIT for different platforms is different. Working with memory on different devices is different. Results will be different, and unpredictable. And the bottleneck will still be not a single line addition, but some kind of disk operation. - PashaPash
  • Exactly. The correct conclusion from the tests - there is no real, tangible difference. - VladD

You are pursuing the wrong goal.

You should not do micro-optimizations, the compiler is doing it now or will do better in the future.

For example, string.Concat has more information about what exactly you want to do, so it can be at least as fast as using StringBuilder in a loop. If it is now slower on your version of the JIT compiler on your platform, it means nothing and may change in the near future. Here, for example, is a (incomplete) list of performance improvements recently introduced in .NET Core 2:

  • Queue<>.Enqueue and Dequeue doubled
  • SortedSet<> accelerated 600 times
  • List<>.Add 1.3 times faster
  • ConcurrentQueue<> accelerated 3.5 times
  • string.StartsWith doubled

and so on.

Thus, BCL shallow performance measurements are relevant only on the version of the library and at the moment when you conduct them.

Optimize better algorithms. The performance gain on this will be much greater than the filtering out of nanoseconds from the underlying data structures.

  • 2
    +1, I’ll add that Core 2 includes changes that directly sped up both StringBuilder and String.Concat, and generally everything that works through Buffer.Memcpy: github.com/dotnet/coreclr/pull/9786 - PashaPash

I wanted to make a note, I want to say about memory (this question is generally asked in exam 70-483 Programming in C #).

'string' (immutable) is immutable, immutable means that if you create a string object, you cannot change it and always create a new 'string' object in memory.

'StringBuilder' (mutable) is a modified mine (That is, it does not create a new object), which means that if you create a 'StringBuilder' object, you can perform any operation, such as insert, replace, or add, without creating a new instance for each time. it will update the string in one place in memory, it will not create a new space in memory.

That is, 'string.Concat ()' it creates a new 'string' object each time. this affects memory because 'string' (immutable) is immutable!