C# .Net: Fastest Way to Convert a String to an Int
This will examine and benchmark many techniques to determine in C# .Net: Fastest way to convert a string to an int.
I ended up working on a project once where I had to read a lot of integers in from a text file. By a lot I mean over 2 million. All those numbers, read in as strings, had to be converted to integers to perform mathematical calculations. When I profiled the code in Visual Studio, I saw that the Convert.ToInt() method was taking a long time (relatively speaking) compared to other parts of the code.
So that’s when this curious consultant started wondering in C# .Net: what is the fastest way to convert a string to an int?
The Set Up:
I wrote a C# Console application to benchmark 4 different 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 a specified array of strings all of which are integers.
2) It then uses 1 of 4 techniques to loop through the string array converting each string representation to the equivalent int, summing up for a total. The 4 techniques are as follows:
3)
# |
Technique |
Code Snippet |
||
T0 |
|
|||
T1 |
|
|||
T2 |
|
|||
T3 |
A custom method which loops through and converts each character in the numeric string |
|
4) The sum from adding up all the values (once converted) is displayed along with the time to verify the accuracy.
5) The string array is cleared out and deleted.
The code assumes all numbers:
- are positive
- do not have thousandths separators or decimal points
- contain no scientific or other special notations
- and all conversions will happen with no exception testing because I’m just wanting to test the raw speed of converting.
I realize some geeks will look at the code and say I’m not comparing apples-to-apples since the Int.TryParse() method under the hood tests for successful conversions, but it is a method commonly used so am including it.
The exe file was run on Windows 7 64-bit with 16 GB memory.
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
Ready! Set! Go!
Before starting, my hypothesis was that I expected it to be a virtual draw between T0 (using Convert.ToInt32() ) and T3 (converting each char to an int in the string).
Let’s see what happened on my machine.
All times are indicated in seconds.milliseconds format. Lower numbers indicate faster performance. Winner marked in green.
|
@ 21,474,836 |
@ 2,147,483 |
@ 250,000 |
@ 50,000 |
@ 1000 |
T0: Convert.ToInt32() |
02.9016051 |
0.2808005 |
0.0312001 |
0.00 |
0.00 |
T1: Int32.TryParse() |
02.8236050 |
0.2652005 |
0.0312000 |
0.0156000 |
0.00 |
T2: Int.Parse() |
02.7612048 |
0.2652005 |
0.0312001 |
0.0156000 |
0.00 |
T3: Custom Method |
00.1872004 |
0.0156001 |
0.00 |
0.00 |
0.00 |
Who opened up the can of whoop ass?!
It’s quite obvious the custom method T3 clearly wins completing in an order of magnitude of at least 10x faster than any of the native C# methods when doing significantly more than 50,000 conversions!!
Last Licks:
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. I’d use those methods for code readability.
If you end up working on a project like I have where you need to do a few million conversions, use the custom method for a 10x conversion performance gain. Knowing what you know now, why would you use anything else??
Obviously you should test on your system before micro-optimizing this functionality in your .Net application.
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 |
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(); TestFastestWayToConvertStringNumberToInt(Int32.MaxValue / 100, 0); TestFastestWayToConvertStringNumberToInt(Int32.MaxValue / 100, 1); TestFastestWayToConvertStringNumberToInt(Int32.MaxValue / 100, 2); TestFastestWayToConvertStringNumberToInt(Int32.MaxValue / 100, 3); TestFastestWayToConvertStringNumberToInt(Int32.MaxValue / 1000, 0); TestFastestWayToConvertStringNumberToInt(Int32.MaxValue / 1000, 1); TestFastestWayToConvertStringNumberToInt(Int32.MaxValue / 1000, 2); TestFastestWayToConvertStringNumberToInt(Int32.MaxValue / 1000, 3); TestFastestWayToConvertStringNumberToInt(250000, 0); TestFastestWayToConvertStringNumberToInt(250000, 1); TestFastestWayToConvertStringNumberToInt(250000, 2); TestFastestWayToConvertStringNumberToInt(250000, 3); TestFastestWayToConvertStringNumberToInt(50000, 0); TestFastestWayToConvertStringNumberToInt(50000, 1); TestFastestWayToConvertStringNumberToInt(50000, 2); TestFastestWayToConvertStringNumberToInt(50000, 3); TestFastestWayToConvertStringNumberToInt(1000, 0); TestFastestWayToConvertStringNumberToInt(1000, 1); TestFastestWayToConvertStringNumberToInt(1000, 2); TestFastestWayToConvertStringNumberToInt(1000, 3); 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 from a string? //Using the Convert.To methods, Int.TryParse/Parse methods, or //parsing each character in the string representation? //For demonstration purposes, we are assuming all strings are valid integers //so there's no checking the format. I know this isn't exactly comparing //apples-to-apples by using TryParse method since the other methods don't //test if it's a valid int or not, but I still wanted to see how well //it performs when doing straight conversions. static void TestFastestWayToConvertStringNumberToInt(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; long total = 0; string[] m = new string[] { "Convert.ToInt32", "Int32.TryParse", "int.Parse", "char-by-char" }; string[] s = new string[NumberOfIterations]; Console.WriteLine("Creating array of string numbers."); Console.WriteLine(); for (int x = 0; x < NumberOfIterations; x++) { s[x] = x.ToString(); } 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++) { total += Convert.ToInt32(s[x]); } end = DateTime.Now; } else if (method == 1) { int y = 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 and allocating "y" isn't counted. for (int x = 0; x < NumberOfIterations; x++) { Int32.TryParse(s[x], out y); total += y; } 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++) { total += int.Parse(s[x]); } end = DateTime.Now; } else if (method == 3) { int y = 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 and allocating "y" isn't counted. for (int x = 0; x < NumberOfIterations; x++) { y = 0; for (int i = 0; i < s[x].Length; i++) { y = y * 10 + (s[x][i] - '0'); } total += y; } end = DateTime.Now; } else { Console.WriteLine("UNKNOWN METHOD!!"); } Console.WriteLine("Finished at: " + end.ToLongTimeString()); Console.WriteLine("Total is: " + total.ToString("#,##0")); Console.WriteLine("Time: " + (end - start)); Console.WriteLine(); Array.Clear(s, 0, s.Length); s = null; Array.Clear(m, 0, m.Length); m = null; GC.Collect(); Console.WriteLine("###########################################################"); Console.WriteLine(); } } } |