|
If your code uses "your way" of doing things often, your colleague's way is better. Performing the operation the way you specified:
string x = "bob" + stringObj + "bob";
actually allocates memory for all three RHS values (iirc), not to mention the fact that string concatenation in itself is not particularly speedy or memory efficient.
However, if you only use it sparingly, or in non-critical sections, your way doesn't really have a problem either. I generally use string concatenation unless performance becomes an issue, in which case I usually switch over to a StringBuilder.
Jeremy Kimball
magnae clunes mihi placent, nec possum de hac re mentiri.
(Large buttocks are pleasing to me, nor am I able to lie concerning this matter)
|
|
|
|
|
Jeremy Kimball wrote:
actually allocates memory for all three RHS values
Actually, it doesn't. The C# compiler compiles simple string concatenation to calls to String.Concat , which only allocates once.
StringBuilder also has interesting issues: see Concatenating with StringBuilders vs strings[^].
Stability. What an interesting concept. -- Chris Maunder
|
|
|
|
|
The strings are still allocated each time:
string s = string.Concat("One", "Two", "Three"); ...still allocates three strings in order to concatenate them.
Microsoft MVP, Visual C#
My Articles
|
|
|
|
|
Not necessarily true: for each, if it's in the intern pool, the interned string will be returned instead of a newly-created object. At least, that's my understanding. (Check the documentation of String.Intern for a starting point.) From this standpoint, if you have commonly-occurring small strings and go assembling them into formatting strings just to use String.Format() , you will incur extra string-creation overhead PLUS the slowness of the method itself!
Regards,
Jeff Varszegi
|
|
|
|
|
The Format version is more costly in performance. However, it is vastly more flexible; you can position the item to be replaced anywhere in the string. You can even place formats in a different order to the order they're passed to Format , or use the same replacement multiple times. This makes it easier to localize displays for different cultures.
Multiple string concatenations with + in the source code are compiled to calls to String.Concat by the C# compiler, and so don't cause any extra overhead in terms of memory usage.
I'd use Format for any strings presented to a user and which therefore might be localized, and + for any internal string operations.
See also Rico Mariani's blog[^] (a performance architect on the .NET Framework team at Microsoft).
Stability. What an interesting concept. -- Chris Maunder
|
|
|
|
|
easier to localize displays for different cultures
Great point. I guess that goes for any output that's configurable, too. -Jeff
|
|
|
|
|
I think that there are two main possible benefits to some approach: simplicity/ease of understanding and maintenance, and performance. On a line-by-line basis, I always lean in favor of performance, so I would advise you to use whatever works fastest. I often perform small benchmarks if I am not sure of which version of a code section would work best; this gives me a good understanding of how code performs, and I constantly add to this knowledge.
I discovered in the past that String.Format() can be pretty slow, and that's what I found this time. Run the code on your setup and see which comes out on top. -Jeff
<br />
string sdlkfj = "sdlkfj";<br />
string someOtherString = "blah";<br />
string formatString = "sdlkfj{0}slkdfj";<br />
string product = null;<br />
<br />
int loopCount = 100000;<br />
long startTime, endTime;<br />
<br />
startTime = DateTime.Now.Ticks * 100;<br />
for(int x = 0; x < loopCount; x++) {<br />
product = sdlkfj + someOtherString + sdlkfj;<br />
product = sdlkfj + someOtherString + sdlkfj;<br />
product = sdlkfj + someOtherString + sdlkfj;<br />
product = sdlkfj + someOtherString + sdlkfj;<br />
product = sdlkfj + someOtherString + sdlkfj;<br />
product = sdlkfj + someOtherString + sdlkfj;<br />
product = sdlkfj + someOtherString + sdlkfj;<br />
product = sdlkfj + someOtherString + sdlkfj;<br />
product = sdlkfj + someOtherString + sdlkfj;<br />
product = sdlkfj + someOtherString + sdlkfj;<br />
}<br />
endTime = DateTime.Now.Ticks * 100;<br />
Console.WriteLine( (((double)(endTime - startTime)) / ((double)(loopCount * 10))) + " nanoseconds" ); <br />
<br />
startTime = DateTime.Now.Ticks * 100;<br />
for(int x = 0; x < loopCount; x++) {<br />
product = String.Format(formatString, someOtherString);<br />
product = String.Format(formatString, someOtherString);<br />
product = String.Format(formatString, someOtherString);<br />
product = String.Format(formatString, someOtherString);<br />
product = String.Format(formatString, someOtherString);<br />
product = String.Format(formatString, someOtherString);<br />
product = String.Format(formatString, someOtherString);<br />
product = String.Format(formatString, someOtherString);<br />
product = String.Format(formatString, someOtherString);<br />
product = String.Format(formatString, someOtherString);<br />
}<br />
endTime = DateTime.Now.Ticks * 100;<br />
Console.WriteLine( (((double)(endTime - startTime)) / ((double)(loopCount * 10))) + " nanoseconds" ); <br />
<br />
|
|
|
|
|
Yes, I will try that for sure.
Thank you.
--------
"I say no to drugs, but they don't listen."
- Marilyn Manson
|
|
|
|
|
|
In this case, it is much better to use a StringBuilder . A String is immutable so anything you do to it allocates a new string and copies the chars. A StringBuilder is mutable so you are changing the same string without re-alloc'ing new strings each time.
Microsoft MVP, Visual C#
My Articles
|
|
|
|
|
Nope. Like you, I often use StringBuilder, especially if I'm constructing a large string in several steps. It's not always faster, though. Try running the code below on your machine-- I came up with these readings:
190.2736 nanoseconds
951.368 nanoseconds
390.5616 nanoseconds
400.576 nanoseconds
Regards,
Jeff Varszegi
<br />
string sdlkfj = "sdlkfj";<br />
string someOtherString = "blah";<br />
string formatString = "sdlkfj{0}slkdfj";<br />
string product = null;<br />
<br />
int loopCount = 100000;<br />
long startTime, endTime;<br />
<br />
<br />
<br />
startTime = DateTime.Now.Ticks * 100;<br />
for(int x = 0; x < loopCount; x++) {<br />
product = sdlkfj + someOtherString + sdlkfj;<br />
product = sdlkfj + someOtherString + sdlkfj;<br />
product = sdlkfj + someOtherString + sdlkfj;<br />
product = sdlkfj + someOtherString + sdlkfj;<br />
product = sdlkfj + someOtherString + sdlkfj;<br />
product = sdlkfj + someOtherString + sdlkfj;<br />
product = sdlkfj + someOtherString + sdlkfj;<br />
product = sdlkfj + someOtherString + sdlkfj;<br />
product = sdlkfj + someOtherString + sdlkfj;<br />
product = sdlkfj + someOtherString + sdlkfj;<br />
}<br />
endTime = DateTime.Now.Ticks * 100;<br />
Console.WriteLine((((double)(endTime - startTime)) / ((double)(loopCount * 10))) + " nanoseconds" ); <br />
<br />
startTime = DateTime.Now.Ticks * 100;<br />
for(int x = 0; x < loopCount; x++) {<br />
product = String.Format(formatString, someOtherString);<br />
product = String.Format(formatString, someOtherString);<br />
product = String.Format(formatString, someOtherString);<br />
product = String.Format(formatString, someOtherString);<br />
product = String.Format(formatString, someOtherString);<br />
product = String.Format(formatString, someOtherString);<br />
product = String.Format(formatString, someOtherString);<br />
product = String.Format(formatString, someOtherString);<br />
product = String.Format(formatString, someOtherString);<br />
product = String.Format(formatString, someOtherString);<br />
}<br />
endTime = DateTime.Now.Ticks * 100;<br />
Console.WriteLine((((double)(endTime - startTime)) / ((double)(loopCount * 10))) + " nanoseconds" ); <br />
<br />
startTime = DateTime.Now.Ticks * 100;<br />
for(int x = 0; x < loopCount; x++) {<br />
product = ((new StringBuilder()).Append(sdlkfj).Append(someOtherString).Append(sdlkfj)).ToString();<br />
product = ((new StringBuilder()).Append(sdlkfj).Append(someOtherString).Append(sdlkfj)).ToString();<br />
product = ((new StringBuilder()).Append(sdlkfj).Append(someOtherString).Append(sdlkfj)).ToString();<br />
product = ((new StringBuilder()).Append(sdlkfj).Append(someOtherString).Append(sdlkfj)).ToString();<br />
product = ((new StringBuilder()).Append(sdlkfj).Append(someOtherString).Append(sdlkfj)).ToString();<br />
product = ((new StringBuilder()).Append(sdlkfj).Append(someOtherString).Append(sdlkfj)).ToString();<br />
product = ((new StringBuilder()).Append(sdlkfj).Append(someOtherString).Append(sdlkfj)).ToString();<br />
product = ((new StringBuilder()).Append(sdlkfj).Append(someOtherString).Append(sdlkfj)).ToString();<br />
product = ((new StringBuilder()).Append(sdlkfj).Append(someOtherString).Append(sdlkfj)).ToString();<br />
product = ((new StringBuilder()).Append(sdlkfj).Append(someOtherString).Append(sdlkfj)).ToString();<br />
}<br />
endTime = DateTime.Now.Ticks * 100;<br />
Console.WriteLine((((double)(endTime - startTime)) / ((double)(loopCount * 10))) + " nanoseconds" ); <br />
<br />
<br />
startTime = DateTime.Now.Ticks * 100;<br />
for(int x = 0; x < loopCount; x++) {<br />
product = ((new StringBuilder(16)).Append(sdlkfj).Append(someOtherString).Append(sdlkfj)).ToString();<br />
product = ((new StringBuilder(16)).Append(sdlkfj).Append(someOtherString).Append(sdlkfj)).ToString();<br />
product = ((new StringBuilder(16)).Append(sdlkfj).Append(someOtherString).Append(sdlkfj)).ToString();<br />
product = ((new StringBuilder(16)).Append(sdlkfj).Append(someOtherString).Append(sdlkfj)).ToString();<br />
product = ((new StringBuilder(16)).Append(sdlkfj).Append(someOtherString).Append(sdlkfj)).ToString();<br />
product = ((new StringBuilder(16)).Append(sdlkfj).Append(someOtherString).Append(sdlkfj)).ToString();<br />
product = ((new StringBuilder(16)).Append(sdlkfj).Append(someOtherString).Append(sdlkfj)).ToString();<br />
product = ((new StringBuilder(16)).Append(sdlkfj).Append(someOtherString).Append(sdlkfj)).ToString();<br />
product = ((new StringBuilder(16)).Append(sdlkfj).Append(someOtherString).Append(sdlkfj)).ToString();<br />
product = ((new StringBuilder(16)).Append(sdlkfj).Append(someOtherString).Append(sdlkfj)).ToString();<br />
}<br />
endTime = DateTime.Now.Ticks * 100;<br />
Console.WriteLine((((double)(endTime - startTime)) / ((double)(loopCount * 10))) + " nanoseconds" ); <br />
|
|
|
|
|
Because you don't reinstantiate the StringBuilder ! You use the same one over:
StringBuilder sb = new StringBuilder();
for (int i=0; i<1000; i++)
{
sb.Append("Some string");
sb.Append(i.ToString());
}
Console.WriteLine(sb.ToString()); Of course it's going to take longer when you keep needlessly reinstanting a StringBuilder .
Microsoft MVP, Visual C#
My Articles
|
|
|
|
|
Aha! But that's done on purpose-- I intentionally duplicated exactly what his code would be doing if it used a StringBuilder. Every instantiation and method call. And as Mike Dimmick pointed out, StringBuilder has certain issues that should be considered.
Regards,
Jeff Varszegi
|
|
|
|
|
I just tested, and even avoiding the extra object creation by resetting the same StringBuilder each time, the StringBuilder solution only improves about ten percent, still about exactly twice as slow as the original poster's preferred method. I can post the code if you want, but I figure it's a snap for you to test yourself if you still don't believe me.
Regards,
Jeff Varszegi
|
|
|
|
|
It's not that I don't believe you, it's just that you were using the StringBuilder "incorrectly". I know that in some cases his preferred way may be better, but in most cases - apparently not this one - it is. Instead of continually calling Append , too, you can also use AppendFormat . I really don't care to see what the difference is, though, I'm just trying to make a point. AppendFormat is, after all, what String.Format is using so I know there's a lot of instructions required that search for the format parameter indexes and apply any format specifications using information from the Type that is in that parameter position, such as checking for IFormattable or using the IFormatProvider to get ICustomFormatter implementations for a specific type.
Microsoft MVP, Visual C#
My Articles
|
|
|
|
|
It's really no problem. I'm just a speed freak when it comes to my code, and I'm constantly fiddling around to see what works fastest, sort of an object-oriented hot rodder. Wotta geek, eh? It's just my thing. I don't claim to be an all-around .NET expert, just pretty good with language features. Some of the questions you answer immediately on this board would take me a while.
I tend to use StringBuilder more now only when constructing large strings (although when I first made the jump from Java I used it religiously). It gives really good performance and lets you write your code in a normal way, without breaking lines. Every time I create one, though, I'm in the habit of just throwing it away; I figure that the bigger the string and related work, the less and less the instantiation of one object matters. Not only that, but if you construct strings of different sizes, and you get a really big one once in a while, I believe the internal char array of a StringBuilder will never shrink, which in some cases could be a problem.
Regards,
Jeff Varszegi
|
|
|
|
|
It just hit me that I might have intentionally confused people. There's loop unrolling in the posted code; I just copied it from an old project and modified. I think that the JIT compiler does its own loop unrolling, so it'd probably turn out about the same, but I unroll loops out of habit sometimes when benchmarking. Guess that makes me a dinosaur, eh?
Regards,
Jeff Varszegi
|
|
|
|
|
Hello,
I have created a TreeView that works fine apart from I can't work on how to get rid of the plus sign and line on the root node.
Does anyone know how to do this? Perhaps it isn't possible?
Thanks,
Matt
Matt Daley
Imutome Limited
Bristol, United Kingdom
matt.daley@imutome.com
|
|
|
|
|
I think you want to set the TreeView's ShowRootLines property to false . Untested suggestion.
Stability. What an interesting concept. -- Chris Maunder
|
|
|
|
|
Opps, Sorry, I forgot to mention that this is a WebControl TreeView, not the Web Form one. The Web Form TreeView has a ShowRootLines property but the WebControl one doesn't.
Matt
Matt Daley
Imutome Limited
Bristol, United Kingdom
matt.daley@imutome.com
|
|
|
|
|
Hello,
I'm wondering, what should I read about if I want to make a bandwidth monitor? And for just making sure what I mean with a bandwidth monitor I mean I want to show how much a user has downloaded and uploaded and how much (fast) he/she is uploading download at the current time =)
Any links? Articles?
I don't need articles specific for making a bandwidth monitor just subjects that when I know them I will proberbly be able to do a bandwidth monitor.
Thanks in advance dear code project members! =)
Martin Lundberg
Student, Sweden
I have to thank every member of the Code Project for making it such a great place for a beginner to learn!
|
|
|
|
|
Yes, I have one here on CP i did ages back, still using it everyday. Search for MyDUMeter.
|
|
|
|
|
Thanks, I'll look into that! =) Do you have any topics that will learn me how to do it myself? I know I can look at your code and try to understand but I would like some article where they explain how things work =)
~~~~~~~~~~~~~~
Martin Lundberg
Student, Sweden
I have to thank every member of the Code Project for making it such a great place for a beginner to learn!
|
|
|
|
|
|
argh! =P what about some articles? =)
|
|
|
|
|