C# .Net: fastest way to convert an int to a string
Here I am going to benchmark several techniques to find the fastest way to convert an int to a string.
All C# programmers have to do this at some point. After testing the fastest way to convert a string to an int (http://cc.davelozinski.com/c-sharp/fastest-way-to-convert-a-string-to-an-int), this curious consultant started wondering in C# .Net: what is the fastest way to convert an int to a string since we do it often enough?
The Set Up:
I wrote a C# Console application to test the following conversion techniques.
The code is written in Visual Studio 2012 targeting .Net Framework version 4.5 x64. The source code is available at the end of this blog so you can benchmark it on your own system if you wish.
In a nutshell, the code does the following:
1) Creates an array of integers.
2) Creates a similar sized array of strings which each int will be converted to. This is to remove time it would take to constantly reassigning a converted int to a single string object (memory allocation, etc) since strings are immutable.
3) It then loops through the string array converting each string representation to the equivalent int, summing up for a total, using one of the techniques below:
# |
Technique |
Code Snippet |
||
T0 |
ToString() |
|
||
T1 |
Convert.ToString() |
|
||
T2 |
String.Format |
|
||
T3 |
Concatenate int and empty string |
|
||
T4 |
Convert int to StringBuilder to string |
|
4) 10 numbers from the string array are then displayed to verify they’re all the same
5) The string and int arrays are cleared out and deleted.
The code assumes all conversions will happen with no exception testing because I’m just wanting to test the raw speed of converting.
The test was run for each technique over the following number of conversions:
- 21,474,836
- 2,147,483
- 250,000
- 50,000
- 1,000
- 100
The Runs:
Before starting, my hypothesis was that I expected technique T0 to be the fastest.
Let’s see what happened on my machine.
All times are indicated in seconds.milliseconds format. Lower numbers indicate faster performance. There are no points for second place:
|
@ 21,474,836 |
@ 2,147,483 |
@ 250,000 |
@ 50,000 |
@ 1000 |
@100 |
T0: .ToString() |
03.8832221 |
0.3588007 |
0.0312001 |
0.0050002 |
0.00 |
0.00 |
T1: Convert.ToString() |
04.1964073 |
0.3588006 |
0.0312000 |
0.0040003 |
0.00 |
0.00 |
T2: string.Format() |
11.2258181 |
0.9512014 |
0.0780002 |
0.0120007 |
0.0010000 |
0.00 |
T3: int + String.Empty |
07.8936139 |
0.7008012 |
0.0624001 |
0.0060004 |
0.00 |
0.00 |
T4: StringBuilder.ToString() |
08.5384884 |
0.8980514 |
0.0840048 |
0.0090005 |
0.00 |
0.00 |
The Results:
I ran the test 3 times. They all pretty much came out the same, so I’m only displaying the results to the first run.
It’s a toss up between T0 and T1 techniques: T0 performed faster over 21 million conversions, but slightly slower at 2 million or less (I would love to know if there’s an application out there where 0.0000001 of a second makes a big performance difference). The other techniques took 2-3 times longer over a substantial number of conversions.
To my surprise, only T2 registered a time @ 1,000 conversions. I was expecting at least 2 or 3 of the techniques to register.
In Summary:
On my system, unless someone spots a flaw in my test code, it really makes no significant performance difference which method is used for anywhere up to a few thousand conversions. Use whatever method makes the most sense.
Over the course of a few million conversions, it looks like the native .ToString() or Convert.ToString() methods are the best way to go.
Obviously you should test on your system before micro-optimizing this functionality for your .Net application.
Here’s the code so you can do so. 🙂
The Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 |
using System; namespace TestApplication { class Program { static void Main(string[] args) { DateTime end; DateTime start = DateTime.Now; Console.WriteLine("### Overall Start Time: " + start.ToLongTimeString()); Console.WriteLine(); TestFastestWayToConvertIntToStringNumber(Int32.MaxValue / 100, 0); TestFastestWayToConvertIntToStringNumber(Int32.MaxValue / 100, 1); TestFastestWayToConvertIntToStringNumber(Int32.MaxValue / 100, 2); TestFastestWayToConvertIntToStringNumber(Int32.MaxValue / 100, 3); TestFastestWayToConvertIntToStringNumber(Int32.MaxValue / 100, 4); TestFastestWayToConvertIntToStringNumber(Int32.MaxValue / 1000, 0); TestFastestWayToConvertIntToStringNumber(Int32.MaxValue / 1000, 1); TestFastestWayToConvertIntToStringNumber(Int32.MaxValue / 1000, 2); TestFastestWayToConvertIntToStringNumber(Int32.MaxValue / 1000, 3); TestFastestWayToConvertIntToStringNumber(Int32.MaxValue / 1000, 4); TestFastestWayToConvertIntToStringNumber(250000, 0); TestFastestWayToConvertIntToStringNumber(250000, 1); TestFastestWayToConvertIntToStringNumber(250000, 2); TestFastestWayToConvertIntToStringNumber(250000, 3); TestFastestWayToConvertIntToStringNumber(250000, 4); TestFastestWayToConvertIntToStringNumber(50000, 0); TestFastestWayToConvertIntToStringNumber(50000, 1); TestFastestWayToConvertIntToStringNumber(50000, 2); TestFastestWayToConvertIntToStringNumber(50000, 3); TestFastestWayToConvertIntToStringNumber(50000, 4); TestFastestWayToConvertIntToStringNumber(1000, 0); TestFastestWayToConvertIntToStringNumber(1000, 1); TestFastestWayToConvertIntToStringNumber(1000, 2); TestFastestWayToConvertIntToStringNumber(1000, 3); TestFastestWayToConvertIntToStringNumber(1000, 4); TestFastestWayToConvertIntToStringNumber(100, 0); TestFastestWayToConvertIntToStringNumber(100, 1); TestFastestWayToConvertIntToStringNumber(100, 2); TestFastestWayToConvertIntToStringNumber(100, 3); TestFastestWayToConvertIntToStringNumber(100, 4); end = DateTime.Now; Console.WriteLine(); Console.WriteLine("### Overall End Time: " + end.ToLongTimeString()); Console.WriteLine("### Overall Run Time: " + (end - start)); Console.WriteLine(); Console.WriteLine("Hit Enter to Exit"); Console.ReadLine(); } //############################################################### //which way is the fastest to convert an int to a string? static void TestFastestWayToConvertIntToStringNumber(int NumberOfIterations, int method) { Console.WriteLine("######## " + System.Reflection.MethodBase.GetCurrentMethod().Name); Console.WriteLine("######## Number of loop iterations: " + NumberOfIterations); Console.WriteLine("######## Test Method: " + method); Console.WriteLine(); DateTime end = DateTime.Now; DateTime start = DateTime.Now; string[] m = new string[] { "ToString()", "Convert.ToString()", "string.Format", "int + String.Empty", "new StringBuilder().Append().ToString()" }; int[] i = new int[NumberOfIterations]; string[] s = new string[NumberOfIterations]; //so time isn't wasted allocating/reassigning memory to a single string variable Console.WriteLine("Creating array of ints."); Console.WriteLine(); for (int x = 0; x < NumberOfIterations; x++) { i[x] = x; } if (method == 0) { Console.WriteLine("Starting method: " + m[method] + " with " + NumberOfIterations.ToString("#,##0") + " iterations. "); start = DateTime.Now; //do this inside the "if" so the time spent on the "if" conditional isn't counted. for (int x = 0; x < NumberOfIterations; x++) { s[x] = i[x].ToString(); } end = DateTime.Now; } else if (method == 1) { Console.WriteLine("Starting method: " + m[method] + " with " + NumberOfIterations.ToString("#,##0") + " iterations. "); start = DateTime.Now; //do this inside the "if" so the time spent on the "if" conditional and allocating "y" isn't counted. for (int x = 0; x < NumberOfIterations; x++) { s[x] = Convert.ToString(i[x]); } end = DateTime.Now; } else if (method == 2) { Console.WriteLine("Starting method: " + m[method] + " with " + NumberOfIterations.ToString("#,##0") + " iterations. "); start = DateTime.Now; //do this inside the "if" so the time spent on the "if" conditional isn't counted. for (int x = 0; x < NumberOfIterations; x++) { s[x] = string.Format("{0}",i[x]); } end = DateTime.Now; } else if (method == 3) { Console.WriteLine("Starting method: " + m[method] + " with " + NumberOfIterations.ToString("#,##0") + " iterations. "); start = DateTime.Now; //do this inside the "if" so the time spent on the "if" conditional and allocating "y" isn't counted. for (int x = 0; x < NumberOfIterations; x++) { s[x] = i[x] + String.Empty; } end = DateTime.Now; } else if (method == 4) { Console.WriteLine("Starting method: " + m[method] + " with " + NumberOfIterations.ToString("#,##0") + " iterations. "); start = DateTime.Now; //do this inside the "if" so the time spent on the "if" conditional and allocating "y" isn't counted. for (int x = 0; x < NumberOfIterations; x++) { s[x] = new StringBuilder().Append(i[x]).ToString(); } end = DateTime.Now; } else { Console.WriteLine("UNKNOWN METHOD!!"); } Console.WriteLine("Finished at: " + end.ToLongTimeString()); Console.WriteLine("Time: " + (end - start)); Console.WriteLine("Samples from conversion: " + Environment.NewLine + s[(int)NumberOfIterations / 10] + " " + s[(int)NumberOfIterations / 9] + " " + s[(int)NumberOfIterations / 8] + " " + s[(int)NumberOfIterations / 7] + " " + s[(int)NumberOfIterations / 6] + " " + s[(int)NumberOfIterations / 5] + " " + s[(int)NumberOfIterations / 4] + " " + s[(int)NumberOfIterations / 3] + " " + s[(int)NumberOfIterations / 2] + " " + s[NumberOfIterations - 1]); Console.WriteLine(); Array.Clear(s, 0, s.Length); s = null; Array.Clear(m, 0, m.Length); m = null; Array.Clear(i, 0, i.Length); i = null; GC.Collect(); Console.WriteLine("###########################################################"); Console.WriteLine(); } } } |