7

Possible Duplicate:
String concatenation vs String Builder. Performance

Any difference (performance and memory usage) between the following two options?

option 1:

StringBuilder msgEntry = new StringBuilder();
msgEntry.AppendLine("<" + timeTag + ">" + timeStamp + "</" + timeTag + ">");

options 2:

StringBuilder msgEntry = new StringBuilder();
msgEntry.Append("<");
msgEntry.Append(timeTag);
msgEntry.Append(">");
msgEntry.Append(timeStamp);
msgEntry.Append("</");
msgEntry.Append(timeTag );
msgEntry.Append(">\n");
Community
  • 1
  • 1
5YrsLaterDBA
  • 33,370
  • 43
  • 136
  • 210
  • 4
    Unless you already have detected a performance problem, or this code is executed thousands of times inside a loop or something, the difference is irrelevant. Go with the most readable option. – JohnFx Jul 20 '10 at 19:10
  • 1
    It may also be worth considering using some of the existing XML classes. It sounds like you may be unfamiliar with quite a lot of the framework (since you weren't aware of the string format functions), I'd recommend picking up something like a 21 day book to read lazily, to learn about those things. – overslacked Jul 20 '10 at 19:13
  • 1
    I vote for reopen: When not used in a loop the performance situation is different! In this specific case, the string concatenation (option 1) would use a single call to String.Concat which performs certainly better than the seven calls to StringBuilder.Append. I was just about to write an answer pointing this out ... – MartinStettner Jul 20 '10 at 20:08
  • @MartinStettner: As I mentioned in my comment, I don't think it's feasible to say for sure which one is better. There are quite a few subtleties going on. However, I've also voted to reopen: not only is it not concatenating in a loop, but the final result is a `StringBuilder`, not a `String` which makes another difference. – Jon Skeet Jul 20 '10 at 20:29
  • @Jon: Right. So, the first option *might* be better (against all advices to *always* use StringBuilder if performance is of importance!) – MartinStettner Jul 20 '10 at 20:44

10 Answers10

27

The second is possibly slightly better in terms of memory use, because it doesn't need to compute the intermediate string1... but it's less readable, IMO.

Personally I'd use:

msgEntry.AppendFormat("<{0}>{1}</{0}>", timeTag, timeStamp);

You haven't shown what you want to do with the StringBuilder afterwards. If you're just going to convert it to a string, then I'd use:

string text = string.Format("<{0}>{1}</{0}>", timeTag, timeStamp);

to start with.

What's the performance like? Well, probably worse - after all, it's got to parse the format string. But unless you've measured this and found it to be the bottleneck, why are you worried?

In general:

  • Make sure your architecture is reasonably efficient - that's hard to change later.
  • Balance your internal design between efficiency and simplicity, with an emphasis on testability; changing the design later may take a while, but it should usually be feasible without compatibility issues.
  • Write your implementation to be as readable as possible.
  • Measure the system to find out whether it performs well enough, and where the bottlenecks are. They're almost never going to be in code like this. (We're not talking about string concatenation in a loop here, after all.)
  • When you've found a bottleneck, try different optimizations and measure them too. Don't assume that something you think will be faster will actually be faster.

1 Or the array to pass to Concat... we don't know the type of timeStamp so we can't tell exactly what's going on there; in the second form it may be appended in-place whereas the first form may need to box it and then convert it to a string before performing the concatenation.

The exact implementation for reallocation etc may well have changed between .NET 3.5 and .NET 4 (I know some bits of the implementation have). Without very careful benchmarking, I'd be really loathe to say which is faster... but the readability is easier to call, albeit subjectively.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • Jon Skeet always faster than everyone else! I was typing that! – Nathan Taylor Jul 20 '10 at 19:07
  • +1 As always...one step ahead. – Justin Niessner Jul 20 '10 at 19:08
  • It's a typing contest sometimes, I tell you... ;) – Willem van Rumpt Jul 20 '10 at 19:09
  • +1 the performance bottleneck is a clever explanation. – P.Brian.Mackey Jul 20 '10 at 19:11
  • I think we need to put a handicap on Jon. Maybe something like delay showing any questions to him by, oh, 45 seconds to give everyone else a head start.. ;) – NotMe Jul 20 '10 at 19:11
  • Ugh... must be a preference thing, because I've never found it as easy to read this type of syntax :D – Jagd Jul 20 '10 at 19:13
  • @Jagd: If you don't like the format version, I'd use concatenation here. – Jon Skeet Jul 20 '10 at 19:17
  • -1 @Jon I like the general advice, but with all due respect it would have been nice to impart something about what to do if a perf bottleneck was discovered like @DOK answer. – Conrad Frix Jul 20 '10 at 19:41
  • @Conrad: So you consider this answer to be actively unhelpful? (That's what I'd normally assume from a -1, as opposed to just not upvoting.) Interesting. I suspect the *vast* majority of the time, the "don't worry about optimization, write for readability" is actually better advice than suggesting that people worry about preallocating StringBuilders with an appropriate size etc. – Jon Skeet Jul 20 '10 at 19:59
  • @JonSkeet: One should point out that in this case the first option is actually better in terms of performance, since only a single call to String.Concat will be made instead of seven calls to StringBuilder.Append (which may even cause multiple reallocation etc...) – MartinStettner Jul 20 '10 at 20:12
  • @MartinStettner: I wouldn't like to be sure. The first form has to create an `object[]` to pass to `Concat`, to start with. Depending on the type of `timeStamp` there may be boxing involved - which may or may not happen with the `Append` code, depending on the exact type. There may or may not be more reallocation going on in the second form, depending on details - including quite possibly the version of the framework. Basically it's too hard to call IMO, and I wouldn't worry about it until I'd been given good reason too. – Jon Skeet Jul 20 '10 at 20:25
  • @JonSkeet: Fully d'accord. But imo it's important to point out that StringBuilder doesn't yield better performance in all circumstances (as it was probably in the early Java days where the pro-StringBuilder-movement originally started :) ...) – MartinStettner Jul 20 '10 at 20:43
  • @Martin: I'll happily go along with that. Of course in this case there's *always* a `StringBuilder` involved, which makes it somewhat unusual. – Jon Skeet Jul 20 '10 at 21:03
  • @Jon. Lets assume the question is, "With a Gadget is it better to frob a blob or star a snu, when you care about goo" A Gadget expert gives the answer "don't worry about goo, unless you know you need to star a snu, you'll only need to star a snu once you've ". This is fine answer and its correct, but to me its incomplete when there exists good rules of thumb e.g. http://blogs.msdn.com/b/ricom/archive/2003/12/02/40778.aspx. The incompleteness is more important and "actively unhelpful" when it comes from some who's "code is the convention" – Conrad Frix Jul 20 '10 at 21:49
  • @Conrad: I'm sorry, but I still completely disagree. Look at my answer for the subtleties involved in which approach (out of the two given in the question) might be faster - it's incredibly hard to tell without more information **and you should measure it if it becomes an issue**. Once you're into the business of measuring, you can find out what makes *your* application faster, rather than using rules of thumb which were written before BCL v2 let alone BCL v4. Measurement is king here: either the performance is irrelevant (as it usually is) or you should measure rather than going "by thumb". – Jon Skeet Jul 20 '10 at 22:53
  • @Conrad: Cool - glad we could agree in the end :) (And the tweaks I made in the answer due to your comments are worthwhile, I think.) – Jon Skeet Jul 21 '10 at 05:22
3

In general, StringBuilder... but when you talk about performance, the only real test is measurement. Especially for LOTS of string changes, StringBuilder is definitely the way to go. For a couple strings... it's probably just easier to append them with the + operator.

Steve
  • 31,144
  • 19
  • 99
  • 122
  • +1 for pointing out that StringBuilder is always better when you have LOTS of string concatenations. – Jagd Jul 20 '10 at 19:10
  • Not in this case! For a single concatenation (outside a loop), a single call to String.Concat would be made for the first option. The second option would take seven calls to StringBuilder.Append. – MartinStettner Jul 20 '10 at 20:13
  • @Martin; "in general". Jon made the same point... Albeit more eloquently than I and with more detail. But the thrust is identical. – Steve Jul 20 '10 at 21:07
2

I would use .AppendFormat(); in that case

StringBuilder msgEntry = new StringBuilder();
msgEntry.AppendFormat("<{0}>{1}</{0}>", timeTag , timeStamp);
Peter Örneholm
  • 2,838
  • 20
  • 24
  • +1 I never noticed that method on a stringbuilder before. That's awesome! no more sb.append(format(...)) for me! – JohnFx Jul 20 '10 at 19:11
2

Personally, I would choose neither, and use

msgEntry.AppendFormat("<{0}>{1}</{0}>", timeTag, timeStamp);
Willem van Rumpt
  • 6,490
  • 2
  • 32
  • 44
1

If that is all you are doing, don't use StringBuilder. It is too much overhead with a readability hit.

Try this:

string.Format("<{0}>{1}</{2}>", timeTag, timeStamp, timeTag);
Brian Genisio
  • 47,787
  • 16
  • 124
  • 167
1

I have relied on the advice in MSDN's Performance Tips and Tricks in .NET Applications which advises to Use StringBuilder for Complex String Manipulation.

It goes on to advise:

Tradeoffs There is some overhead associated with creating a StringBuilder object, both in time and memory. On a machine with fast memory, a StringBuilder becomes worthwhile if you're doing about five operations. As a rule of thumb, I would say 10 or more string operations is a justification for the overhead on any machine, even a slower one.

I would also consider this advice from a code optimization .Net show:

It is especially important to pre-allocate the size of the string. If you don't, StringBuilder is still faster, but if you can predict the ultimate length of the final string, set it in advance.

That is because the default capacity of a StringBuilder is 16. It automatically resizes when capacity is exceeded -- it doubles every time. So, you may have several unnecessary resizings if you don't set the initial capacity. You can count up the maximum expected number of characters in your example, and initialize the StringBuilder so that it won't resize. That will save some CPU.

And here is some additional advice from MSDN:

The performance of a concatenation operation for a String or StringBuilder object depends on how often a memory allocation occurs. A String concatenation operation always allocates memory, whereas a StringBuilder concatenation operation only allocates memory if the StringBuilder object buffer is too small to accommodate the new data. Consequently, the String class is preferable for a concatenation operation if a fixed number of String objects are concatenated. In that case, the individual concatenation operations might even be combined into a single operation by the compiler. A StringBuilder object is preferable for a concatenation operation if an arbitrary number of strings are concatenated; for example, if a loop concatenates a random number of strings of user input.

DOK
  • 32,337
  • 7
  • 60
  • 92
  • I would start off by finding out whether or not it's actually significant before worrying about computing the right size to pre-allocate etc. It's also worth noting that your first link is from August 2001... before .NET 1.0 even came out. I know for certain that StringBuilder's implementation has changed significantly between .NET 3.5 and .NET 4, and I wouldn't be surprised if it had changed in other versions too. It's still worth avoiding concatenation in loops, sure... but rules of thumb can certainly change over time. – Jon Skeet Jul 20 '10 at 20:02
  • @Jon Skeet I realize the first article isn't recent, but it's still cited often, and if it was no longer valid, I would think Microsoft staff would remove or update it. And in the third article, which applies to .Net 4, they mention the resizing in "Performance Considerations". And since it is sometimes very easy to calculate the maximum capacity needed for a StringBuilder, as it would be in this case, I would definitely do it if string concatenations are frequent in the app. It's such a small effort. – DOK Jul 20 '10 at 20:40
  • How frequent is frequent? I wouldn't do it unless you've got a good reason to. How much effort would you say it is in this case? What about when you're reading the code? How are you going to work out the length of `timeStamp`? – Jon Skeet Jul 20 '10 at 20:55
0

The second line is better as your not getting much if any benifit from stringbuilder in the first. However for a small string concat like that I wouldn't bother with stringbuilder

David
  • 560
  • 4
  • 13
0

Yes.

If you're going to do option 1, there's no point in using a StringBuilder. You're still doing string concatenation and will end up with multiple extra temp strings being created and discarded in-memory.

For something like this, you should probably use String.Format()

Toby
  • 7,354
  • 3
  • 25
  • 26
  • There's only one extra temporary string required here - the compiler will call `string.Concat("<", timeTag, ">", timeStamp, "", timeTag, ">")` (with conversions where necessary). – Jon Skeet Jul 20 '10 at 19:11
0

The first example seems wrong to me. What's the point of creating StringBuider object when you are concatenating strings before passing them to the StringBuilder?

Also note that:

  • Append returns instance of StringBuilder, so calls to Append and AppendLine can be chained together
  • At the end of second example you can use AppendLine(">") instead of Append(">\n")
    StringBuilder msgEntry = new StringBuilder();
    msgEntry.Append("<")
        .Append(timeTag)
        .Append(">")
        .Append(timeStamp)
        .Append("</")
        .Append(timeTag )
        .AppendLine(">");

Personally I'd do

    string.Format("<{0}>{1}</{0}>", timeTag, timeStamp);

unless you need the StringBuilder for something else.

Michał Piaskowski
  • 3,800
  • 2
  • 34
  • 46
-1

Always use StringBuilder.Append() for string concatenation. The string + operator causes new allocation for each new item.

Florian Reischl
  • 3,788
  • 1
  • 24
  • 19
  • 1
    No it doesn't. It will call `string.Concat` once, so it will generate one extra intermediate string. You should only use `StringBuilder.Append()` when it actually makes sense to do so - if you're doing all the concatenation in a single expression and want a string out at the end, using + is absolutely fine. – Jon Skeet Jul 20 '10 at 19:10
  • Well, just did a short test. Apparently I've been wrong. Thanks for the correction. – Florian Reischl Jul 20 '10 at 19:18
  • If you have adjacent static strings separated with the "+", the compiler will combine them at compile-time. Also, if only concatenating 2 or 3 strings, "+" outperforms instantiating a stringbuilder object. – adam0101 Jul 20 '10 at 19:20