struct mydata
{
public int id;
public string data;
}
class Program
{
static void Main(string[] args)
{
List<mydata> myc = new List<mydata>();
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
for (int i = 0; i < 1000000; i++)
{
mydata d = new mydata();
d.id = i;
d.data = string.Format("DataValue {0}",i);
myc.Add(d);
}
stopwatch.Stop();
Console.WriteLine("End: {0}", stopwatch.ElapsedMilliseconds);
}
Whys is this code above so SLOW..?
On an older laptop the times are:
C# code above: 1500ms
Similar code in Delphi: 450ms….
I then changed the code to a KeyValue/Pair (see below):
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start(); var list = new List<KeyValuePair<int , string>>(); for (int i = 0; i < 1000000; i++) { list.Add(new KeyValuePair<int,string>(i, "DataValue" + i)); } stopwatch.Stop(); Console.WriteLine("End: {0}", stopwatch.ElapsedMilliseconds); Console.ReadLine();This improved the time to 1150ms..
If I remove the '+ i' the time is < 300ms
If I try and replace it with a StringBuilder, the timing is similar.
StringBuilder sb = new StringBuilder(); Stopwatch stopWatch = new Stopwatch(); stopWatch.Start(); var list = new List<KeyValuePair<int, string>>(); for (int i = 0; i < 1000000; i++) { sb.Append("DataValue"); sb.Append(i); list.Add(new KeyValuePair<int, string>(i, sb.ToString())); sb.Clear(); } stopWatch.Stop(); Console.WriteLine("End: {0}", stopWatch.ElapsedMilliseconds); Console.ReadLine();Is slightly better.. If you remove the sb.Append(i) its very fast..
It would appear that any time you have to add an Int to a string/stringbuilder its VERY SLOW..
Can I speed this up in any way ??
EDIT **
The code below is the quickest I can get after making suggestions:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Diagnostics; using System.Threading;
namespace ConsoleApplication1 { struct mydata { public int id; public string data; }
class Program { static void Main(string[] args) { List<mydata> myc = new List<mydata>(); Stopwatch stopwatch = new Stopwatch(); stopwatch.Start(); for (int i = 0; i < 1000000; i++) { mydata d = new mydata(); d.id = i; d.data = "DataValue " + i.ToString(); myc.Add(d); } stopwatch.Stop(); Console.WriteLine("End: {0}", stopwatch.ElapsedMilliseconds); Console.ReadLine(); } }}
If I replace the line:
d.data = "DataValue " + i.ToString();
with:d.data = "DataValue ";On my home machine this goes from 660ms -> 31ms..
Yes.. its 630ms slower with the '+ i.ToString()'
But still 2x faster than boxing/string.format etc etc..
Stopwatch stopwatch = new Stopwatch();stopwatch.Start(); var list = new List<KeyValuePair<int, string>>(); for (int i = 0; i < 1000000; i++) { list.Add(new KeyValuePair<int, string>(i, "DataValue" +i.ToString())); } stopwatch.Stop(); Console.WriteLine("End: {0}", stopwatch.ElapsedMilliseconds); Console.ReadLine();is 612ms.. (no difference in speed if List>(1000000); is pre-initialised).
The problem with your first two examples is that the integer must first be boxed and then converted to a string. The boxing causes the code to be slower.
For example, in this line:
the second parameter to
string.Formatisobject, which causes boxing ofi. See the intermediate language code for confirmation of this:Similarly this code:
is equivalent to this:
This uses the overload of
String.Concatwith parameters of typeobjectso again this involves a boxing operation. This can be seen in the generated intermediate language code:For better performance this approach avoids the boxing:
Now the intermediate language code doesn’t include the
boxinstruction and it uses the overload ofString.Concatthat takes two strings: