Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Performance creating concatenated strings

Which way to create strings is more run time efficient in C#

Number 1:

bool value = true;
int channel = 1;
String s = String.Format(":Channel{0}:Display {1}", channel, value ? "ON" : "OFF");

Number 2:

bool value = true;
String channel = "1";
string  s = ":Channel" + channel + ":Display " + value ? "ON" : "OFF";
like image 930
Razer Avatar asked Mar 10 '13 21:03

Razer


2 Answers

I'm going to add an example now to illustrate how the compiler treats the two, because there seems to be a lot of confusion in some of the other answers (edit: note that much of these confusions have now been deleted/edited away):

bool value = true;
int channel = 1;
String s = String.Format(":Channel{0}:Display {1}", channel,
    value ? "ON" : "OFF");

The last line is compiled as:

String s = String.Format(":Channel{0}:Display {1}",
    new object[2] {(object)channel, value ? "ON" : "OFF")};

note interestingly the creation of an array and a "box" for int channel, and of course the extra parsing required to find {0} / {1}.

Now Number 2:

bool value = true;
String channel = "1";
string  s = ":Channel" + channel + ":Display " + (value ? "ON" : "OFF");

The last line is compiled as:

string s = string.Concat(":Channel", channel, ":Display ", value ? "ON" : "OFF");

here there is no array, no box (channel is now a string), and no parsing. The overload is public static string string.Concat(string,string,string,string); string.Concat is implemented very efficiently, pre-allocating a right-sized string in advance then over-writing, etc.

In most code, either is fine. The second version is technically more efficient (no box, no array, no parsing), but is a major pain if you ever want to internationalize later. In most applications you will not notice any difference between the two. The parsing is fast, and the box / array are collected cheaply as gen-zero objects. But cheap is not free.

like image 145
Marc Gravell Avatar answered Oct 13 '22 00:10

Marc Gravell


This could help you to test this yourself. This was executed using .net v4.0.30319 runtime.

sw = new System.Diagnostics.Stopwatch();

// Number 1
bool value = true;
int channel = 1;
sw.Start();
for (int i = 0; i <= 100000; i++)
{
    String s = String.Format(":Channel{0}:Display {1}", channel, value ? "ON" : "OFF");
}
sw.Stop();

sw.Reset();

// Number 2
sw.Start();
for (int i = 0; i <= 100000; i++)
{
    string s = "Channel" + channel + ":Display " + (value ? "ON" : "OFF");
}
sw.Stop();

My result is:

Number 1: 136ms

Number 2: 91ms

So the second option has better performance. The fact that the first option uses an extra method call (string.Format()) and replacing parameters (as Marc remarked) is what makes the difference.

If instead of using 100.000 iterations I use 1.000.000, this is what I get

Number 1: 1308ms

Number 2: 923ms

Basically, same conclusion.

like image 36
Claudio Redi Avatar answered Oct 13 '22 00:10

Claudio Redi