4

What is more efficient in performance to prepend a string to another?

Using the StringBuilder.Insert method or the string.Concat method?

messageString.Insert(0, prependedString);

or

string.Concat(prependedString, messageString);

In my case the message string is relatively big, the prepended string is short.

Yousha Aleayoub
  • 4,532
  • 4
  • 53
  • 64
Christoph Brückmann
  • 1,373
  • 1
  • 23
  • 41
  • for huge strings use string builder. otherwise a normal concat (same as `+` operator.) – M.kazem Akhgary Sep 25 '15 at 09:52
  • 3
    If you're concating more than two strings use `StringBuilder`. – Bauss Sep 25 '15 at 09:53
  • @Bauss thats not efficient. stringbuilder takes much more time to instantiate than a normal concat. – M.kazem Akhgary Sep 25 '15 at 09:56
  • I just concat two strings. – Christoph Brückmann Sep 25 '15 at 10:00
  • 2
    @M.kazemAkhgary that is *not true*. In fact, StringBuilder is preferred for exactly this reason - concatenating strings forces multiple temporary string allocations while a StringBuilder manipulates only a single buffer. Those temporary strings remain until the GC collects them, which results in CPU waste as well. Over time, these allocations can cause performance problems – Panagiotis Kanavos Sep 25 '15 at 10:00
  • @ChristophBrückmann - the answer depends on how many strings you are concatenating, and how big they are. – user1666620 Sep 25 '15 at 10:03
  • @PanagiotisKanavos I agree. but we dont know how OP is dealing with it. stringbuilder can be efficient if for example it self is not created inside loop. – M.kazem Akhgary Sep 25 '15 at 10:03
  • 1
    @ChristophBrückmann there are a *lot* of articles on the matter. Concatenating two strings creates a third. Concatenating three, creates a fourth. Each of them requires the allocation of a buffer, which stays in memory until the Garbage collector runs. In fact, too many temporary strings can force a Garbage collection. This is annoying in desktop applications but can be *very* bad in busy server or web applications - the number of zombies adds up and the server has to stop processing and wait for GC to collect them – Panagiotis Kanavos Sep 25 '15 at 10:03
  • 1
    @M.kazemAkhgary why would anyone keep instantiating a new stringbuilder inside a loop? – user1666620 Sep 25 '15 at 10:04
  • @PanagiotisKanavos I thought small things like strings typically sit on the gen 1 heap and get collected pretty much constantly (as opposed to one large collection that halts your server). – Asad Saeeduddin Sep 25 '15 at 10:06
  • 1
    Even if background garbage collection is enabled, CPU time is CPU time - even if it runs in another core, it *still* steals cycles from processing. – Panagiotis Kanavos Sep 25 '15 at 10:09
  • Possible Duplicate: http://stackoverflow.com/questions/32779506/performance-stringbuilder-insert-versus-string-concat/32780119#32780119 – Tamir Vered Sep 25 '15 at 10:27

2 Answers2

8

string.Concat is the fastest method if the number of items is fixed. This statement holds true in all cases. It does not matter how long the strings are.

string.Concat calculates the final string size and then copies over the bits into a freshly allocated string. It cannot be done any faster.

In fact, you should write a + b instead of calling Concat (if that is possible in the specific situation).

for huge strings use string builder

False. Why would that be the case?!

If you're concating more than two strings use StringBuilder

False. If the number is fixed, use Concat. StringBuilder gains you nothing but adds overhead.

the answer depends on how many strings you are concatenating, and how big they are

False. The algorithm that I described above is always the fastest possible solution.

The myths around StringBuilder are an amazing variety. If you understand how both options work internally you can answer all these questions yourself. I did not study and memorize all these answers. I generate them from my understanding of internals.

usr
  • 168,620
  • 35
  • 240
  • 369
  • I agree with everything you've said, but just to avoid any misconceptions, we *should* use `StringBuilder` when frequently mutating a string, right? For memory reasons, if nothing else. – Asad Saeeduddin Sep 25 '15 at 10:10
  • @Asad you can't mutate a string so I assume you mean a dynamic number of operations on a temporary string. Then, StringBuilder usually is the right choice. I find this to be exceedingly rare in practice. The only case where this is often being done is concatenating a sequence of some sort. We have string.Join for that. – usr Sep 25 '15 at 10:11
  • You limited the (very vague) question to a very limited case - not just fixed strings, but the number is known at compile time. Performance isn't only about clock time, or how fast a single operation executes. – Panagiotis Kanavos Sep 25 '15 at 10:11
  • "Building a string", if you prefer. By string, I mean a string of characters, conceptually, as opposed to the type. As far as use cases go, building large log outputs from the wrong kind of string concatenation often causes bottlenecks. – Asad Saeeduddin Sep 25 '15 at 10:12
  • @PanagiotisKanavos in the comments he clarifies that he wants to join just those two strings. Let's wait for the OP to respond. – usr Sep 25 '15 at 10:12
  • @usr When you need to iterate over a collection of strings in order to join them, you're going to favor `StringBuilder` over concatenating each variable with the previous. Or perhaps even the built in `string.Join` – Yuval Itzchakov Sep 25 '15 at 11:12
  • @YuvalItzchakov yeah, I did not mean to imply anything to the contrary. On the other hand if you have a string[] you can also use string.Concat which is the fastest option in that case. But a collection is not a fixed amount so my answer does not apply. – usr Sep 25 '15 at 11:15
  • @YuvalItzchakov `string.Concat` has an overload accepting an `IEnumerable` (among other variations for sequences of items to concat) so it is perfectly capable of concatting a number of strings not known at compile time. `string.Join` is effectively the same thing, but adds a common string between each item in the sequence. That is sometimes needed, but often not, and when it's not, `string.Concat` is the appropriate tool for the job. The implementation of those overloads is functionally the same as using a `StringBuilder` (but it's much shorter and semantically meaningful). – Servy Sep 25 '15 at 13:46
  • @PanagiotisKanavos See my previous comment; `string.Concat` isn't just for when the number of strings is known at compile time. – Servy Sep 25 '15 at 13:47
3

This is a duplicate of How to use StringBuilder Wisely you can read my full answer over there, in short:

Concat function is faster than working with StringBuilder for the number of strings entering the function is known.

Community
  • 1
  • 1
Tamir Vered
  • 10,187
  • 5
  • 45
  • 57
  • 1
    Thank god someone has written a good answer on this. Welcome to Stack Overflow, btw! – usr Sep 25 '15 at 10:25
  • Thanks and... i'm not new ^^; – Tamir Vered Sep 25 '15 at 10:27
  • But you've only recently started answering a significant amount of questions. I have noticed. – usr Sep 25 '15 at 10:28
  • Yes indeed, thanks :) – Tamir Vered Sep 25 '15 at 10:28
  • 1
    Actually I was looking for an answer which focuses on prepending a string via a StringBuilder or a string method itself. I'm creating the messageString via a StringBuilder which actually has a performance benefit. This messageString could finally be empty or a couple of dozen lines long. If the messageString is finally not empty an aditional string sould be prepended. Especially there my assumption was that using the StingBuilder would not be effective because the whole string inside the builder needs to be some kind of shifted. But I don't really know how it works internally. – Christoph Brückmann Sep 25 '15 at 14:30
  • @ChristophBrückmann the link refers to `String.Concat` and explains what happens when you do `myString += otherString`. It also explains when it is effective to use `StringBuilder`. – Tamir Vered Sep 25 '15 at 14:32
  • @Some1Pr0 Yes, which in fact is interesting and gave me a better understanding. But it does not really answer my question. It seems that I was not able to ask properly. :) – Christoph Brückmann Sep 25 '15 at 14:37
  • In any case, using the `string` method itself will allocate a whole new full `string` for the result, when you use `StringBuilder`, the creation of the new `string` will only occur when you use the `StringBuilder.ToString` method which means if you are just prepending one `string` there is no difference but when you prepend 30 you should use `StringBuilder`. – Tamir Vered Sep 25 '15 at 14:39
  • 1
    The `string` in the `StringBuilder` does not shift since the `StringBuilder` contains the 2 of your `strings` and their position until you use its `ToString` method, which mean prepending just add your `string` to the head of the list and waits. – Tamir Vered Sep 25 '15 at 14:41
  • @Some1Pr0 Okay, thanks. :) – Christoph Brückmann Sep 25 '15 at 15:55
  • @TamirVered that's not true. The characters _are_ shifted. It even says so in the [documentation](https://learn.microsoft.com/en-us/dotnet/api/system.text.stringbuilder.insert?view=netcore-3.1) (section "Remarks"). If you check the source, you will see that `Insert()` calls `MakeRoom()` and `ReplaceInPlaceAtChunk()`. So to answer OP's question: don't use `StringBuilder.Insert()` repeatedly like you would use `Append()`. It likely will have the opposite effect, and be much slower than simple string concatenation. – Good Night Nerd Pride Aug 18 '20 at 16:54