Feature Request: Add String.Concat to performance warnings C# .NET 4.5

Hello,

Would it be possible to add a warning regarding String.Concat in .NET 4.5?

There is an issue reported on Microsoft's Connect website: https://connect.microsoft.com/VisualStudio/feedback/details/780770/string-concat-slow-in-net-4-5#details

Looking at the results, it appears that String.Concat is up to 200 times slower than similar operations. Microsoft have given a workaround, but not a solution.

Given the large difference in the results (if it were only a few ms I wouldn't ask), I think it would be important to tell people that potentially they could kill the performance of their application.

10 comments
Comment actions Permalink

Hi,

Thanks for the suggestion - I've logged it here: http://youtrack.jetbrains.com/issue/RSRP-373571.
You're weelcome to vote for it and monitor its status there.

Thanks again!

0
Comment actions Permalink

Thanks for that Alex!

Didn't realise you had youtrack, obviously wasn't looking hard enough! ;)

0
Comment actions Permalink

You do realise that the code in your article doesn't produce the same string in 3.5 as it does in 4.5? In 4.5, you'll get the same 10000 character string back; in 3.5, you'll just get the result of calling ToString on the list you've passed in.

The performance of String.Concat still sucks, but it's no worse in 4.5 than it was in previous versions.

0
Comment actions Permalink
I pointed that out in the article I wrote already...The point of reporting it was that this new overload has taken over from previous functionality, personally I never use String.Concat anyway (nor the operator overload) but I thought it was important that this was flagged up. Microsoft rightly pointed out that the workaround is to use the object cast.PS. Why don't linebreaks work in IE10?
0
Comment actions Permalink

Did you try it? Running the following in 3.5:

char[] test = new char[] { 'a', 'b', 'c' };
string s = string.Concat(test);
Console.WriteLine(s);


produces the following output:

System.Char[]


The code is calling the Concat(Object) overload, not the Concat(Object[]) overload.

The workaround that Microsoft suggested suffers from the same problem: the string you get back isn't what you were expecting.

Changing your code so that it works as expected in 3.5 actually shows significantly worse performance than in 4.5, possibly due to the fact that you have to convert the Char array to a String array before you can call the methods.

You'll also find that your StringBuilder method doesn't work as expected in 4.5; there is no Append overload which accepts an IEnumerable<Char>, so only the Char array test produces the correct output.

0
Comment actions Permalink

OK, so you've edited your post and completely changed what you said, which now makes my other response look odd.

The only place I can see in your article which mentions this problem is a comment by "Ketsuekiame", which seems to have been ignored.

Running your code in 3.5 produces the wrong output. The only case where it would produce the correct output in 3.5 with better performance than 4.5 is if you pass a single String to the Concat method; 3.5 would call Concat(Object), whereas 4.5 would call Concat<Char>(IEnumerable<Char>). In every other case, the 3.5 code will not work as expected.

The performance might suck, but I'll take slow code which produces the correct output over fast code which produces garbage any day!

0
Comment actions Permalink
Yeah sorry about that, I thought I'd managed to catch it befor eyou logged on. I understand what you're saying now. I will revise my test.
0
Comment actions Permalink

Thank you for pointing out the problem with the testing. :)

It seems String.Concat in IEnumerable<Char> is quick, possibly because it has a direct route turn it into a String?

Otherwise yes, String.Concat performance is diabolical :)

0
Comment actions Permalink

The reason your IEnumerable<Char> test works is because the variable already contains a String:

String perfString = RandomString(10000);
IEnumerable<Char> numCharString = perfString.AsEnumerable();


The AsEnumerable method simply returns the input parameter, which means that numCharString has a compile-time type of IEnumerable<Char>, but a run-time type of String. When you pass that to the String.Concat(Object) method, it calls ToString on the parameter. Calling ToString on a String returns the same String, so this appears to work.

If you change your code to use an IEnumerable<Char> which isn't a String, you'll see the same problem as the other tests:

String perfString = RandomString(10000);
IEnumerable<Char> numCharString = perfString.Select(c => c);

myString = String.Concat(numCharString);
// Returns "System.Linq.Enumerable+WhereSelectEnumerableIterator`2[System.Char,System.Char]"

0
Comment actions Permalink

Yes, that's what I meant by a direct route, sorry sometimes I'm not clear with language.

0

Please sign in to leave a comment.