C# TryParse Vs Try Catch
This article details the C# benchmark showdown between TryParse Vs Try Catch performance.
C# programmers are undoubtedly familiar with the multiple ways data can be parsed to verify good data while also handling bad data.
Each has its advantages and disadvantages depending on the context. I believe most developers would suggest:
- the Try Catch approach in framework and back-end programming because more information can be given to the client about the error
- using TryParse if you don’t care about why something fails
What isn’t often considered are the performance implications.
Exception handling is expensive. But this Curious Consultant is wondering how expensive?
Let’s find out!
The pre-amble about the code and set up
3 string arrays are initialized with 20 string representations of int, bool, and DateTime values. The first 19 are valid; the last value is the string “hello” to purposely cause an exception 5% of the time.
The code then performs the conversions using the TryParse methods followed by the Try Catch structure.
The C# is written in Visual Studio 2015 targeting .Net Framework version 4.7.1 x64. The source code is available at the end of this blog so you can benchmark it on your own system.
Which way came out on top?
Because exception handling is naturally expensive, in this TryParse Vs Try Catch race we’re expecting TryParse to come out on top.
But let’s see what happened on my machine.
All times are indicated in seconds.milliseconds format.
Lower numbers indicate faster performance. Winners marked in green.
|
1,000 |
10,000 |
100,000 |
1,000,000 |
10,000,000 |
00.0000817 |
00.0007766 |
00.0075907 |
00.0820211 |
00.8331172 |
|
int Try Catch |
00.0100096 |
00.0197005 |
00.1265200 |
01.5656189 |
13.2879841 |
|
|||||
00.0000181 |
00.0001690 |
00.0010283 |
00.0082409 |
00.0790119 |
|
bool Try Catch |
00.0015470 |
00.0130745 |
00.1482046 |
01.4293894 |
13.8321639 |
|
|||||
00.0001125 |
00.0007083 |
00.0077886 |
00.0784932 |
00.7890670 |
|
DateTime Try Catch |
00.0023502 |
00.0167284 |
00.1756736 |
01.7237376 |
18.0333234 |
The winner – 100x faster!
Unless someone spots a flaw in my code, when there’s a need for speed, the TryParse methods are the only ones that should be considered! Just look at the numbers and time differences! It blew the Try Catch construct out of the water – being 100x faster when there’s an exception 5% of the time.
Check out the speed differences at the 1 million and especially at the 10 million counts where Try-Catch took at least 13 seconds compared to TryParse taking less than a second.
Cool stuff. 🙂
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 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 |
using System; using System.Collections.Generic; using System.Collections; using System.Collections.Concurrent; using System.Data; using System.Data.Sql; using System.IO; using System.Linq; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; using System.Threading; using System.Diagnostics; namespace TestApplication { class Program { static void Main(string[] args) { DateTime end; DateTime start = DateTime.Now; Console.WriteLine("### Overall Start Time: " + start.ToLongTimeString()); Console.WriteLine(); TestTryParseVsTryCatch(1000); TestTryParseVsTryCatch(10000); TestTryParseVsTryCatch(100000); TestTryParseVsTryCatch(1000000); TestTryParseVsTryCatch(10000000); 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(); } //#################################################### //Compare the speed differences: tryparse vs try catch //construct. Let's see which is faster. //Code from http://cc.davelozinski.com/c-sharp/c-tryparse-vs-try-catch static void TestTryParseVsTryCatch(int numberOfIterations) { Console.WriteLine("######## " + System.Reflection.MethodBase.GetCurrentMethod().Name); Console.WriteLine("Number of values to convert: " + numberOfIterations.ToString("#,##0")); Stopwatch sw = new Stopwatch(); DateTime end = DateTime.Now; DateTime start = DateTime.Now; int initializecount = 20; string[] i = new string[initializecount]; string[] b = new string[initializecount]; string[] dt = new string[initializecount]; int i_result; bool b_result; DateTime dt_result; bool succeeded; //Initialize the arrays which hold the values we'll be parsing //making sure that at least 1 will always throw an exception. //1 out of every 20 == 5%, which I think a fair estimate //to say 5% of data will be bad. for (int x=0; x<initializecount; x++) { if (x == initializecount - 1) { //create the invalid strings (eg, bad data) to throw an exception i[x] = "hello"; //put in an invalid int b[x] = "hello"; //put in an invalid boolean dt[x] = "hello";//put in an invalid datetime } else { //create valid strings that we'll be later parsing i[x] = x.ToString(); b[x] = true.ToString(); dt[x] = (new DateTime()).ToString(); } } Console.WriteLine("###########################################################"); Console.WriteLine("Starting int.TryParse() test " + numberOfIterations.ToString("#,##0") + " at: " + DateTime.Now.ToLongTimeString()); sw.Restart(); for (int x = 0; x < numberOfIterations; x++) { succeeded = int.TryParse(i[x % initializecount], out i_result); } sw.Stop(); Console.WriteLine("Finished at: " + DateTime.Now.ToLongTimeString()); Console.WriteLine("Time to run: " + sw.Elapsed.ToString("mm\\:ss\\.fffffff")); Thread.Sleep(500); Console.WriteLine("###########################################################"); Console.WriteLine("Starting int Try Catch test " + numberOfIterations.ToString("#,##0") + " at: " + DateTime.Now.ToLongTimeString()); sw.Restart(); for (int x = 0; x < numberOfIterations; x++) { try { i_result = Convert.ToInt32(i[x % initializecount]); } catch { } } sw.Stop(); Console.WriteLine("Finished at: " + DateTime.Now.ToLongTimeString()); Console.WriteLine("Time to run: " + sw.Elapsed.ToString("mm\\:ss\\.fffffff")); Thread.Sleep(500); Console.WriteLine("###########################################################"); Console.WriteLine("Starting bool.TryParse() test " + numberOfIterations.ToString("#,##0") + " at: " + DateTime.Now.ToLongTimeString()); sw.Restart(); for (int x = 0; x < numberOfIterations; x++) { succeeded = bool.TryParse(b[x % initializecount], out b_result); } sw.Stop(); Console.WriteLine("Finished at: " + DateTime.Now.ToLongTimeString()); Console.WriteLine("Time to run: " + sw.Elapsed.ToString("mm\\:ss\\.fffffff")); Thread.Sleep(500); Console.WriteLine("###########################################################"); Console.WriteLine("Starting bool Try Catch test " + numberOfIterations.ToString("#,##0") + " at: " + DateTime.Now.ToLongTimeString()); sw.Restart(); for (int x = 0; x < numberOfIterations; x++) { try { b_result = Convert.ToBoolean(b[x % initializecount]); } catch { } } sw.Stop(); Console.WriteLine("Finished at: " + DateTime.Now.ToLongTimeString()); Console.WriteLine("Time to run: " + sw.Elapsed.ToString("mm\\:ss\\.fffffff")); Thread.Sleep(500); Console.WriteLine("###########################################################"); Console.WriteLine("Starting DateTime.TryParse() test " + numberOfIterations.ToString("#,##0") + " at: " + DateTime.Now.ToLongTimeString()); sw.Restart(); for (int x = 0; x < numberOfIterations; x++) { succeeded = DateTime.TryParse(dt[x % initializecount], out dt_result); } sw.Stop(); Console.WriteLine("Finished at: " + DateTime.Now.ToLongTimeString()); Console.WriteLine("Time to run: " + sw.Elapsed.ToString("mm\\:ss\\.fffffff")); Thread.Sleep(500); Console.WriteLine("###########################################################"); Console.WriteLine("Starting DateTime Try Catch test " + numberOfIterations.ToString("#,##0") + " at: " + DateTime.Now.ToLongTimeString()); sw.Restart(); for (int x = 0; x < numberOfIterations; x++) { try { dt_result = Convert.ToDateTime(dt[x % initializecount]); } catch { } } sw.Stop(); Console.WriteLine("Finished at: " + DateTime.Now.ToLongTimeString()); Console.WriteLine("Time to run: " + sw.Elapsed.ToString("mm\\:ss\\.fffffff")); Console.WriteLine(); } } //class } //namespace |