Performance Cost of 'Try' in C#

Performance cost of a try/catch block

From MSDN site:

Finding and designing away
exception-heavy code can result in a
decent perf win. Bear in mind that
this has nothing to do with try/catch
blocks: you only incur the cost when
the actual exception is thrown. You
can use as many try/catch blocks as
you want. Using exceptions
gratuitously is where you lose
performance. For example, you should
stay away from things like using
exceptions for control flow.

Also see these related SO questions: (1) (2) (3) and (4).

Performance Cost Of 'try' in C#

The performance cost of try is very small. The major cost of exception handling is getting the stack trace and other metadata, and that's a cost that's not paid until you actually have to throw an exception.

But this will vary by language and implementation. Why not write a simple loop in C# and time it yourself?

What is the real overhead of try/catch in C#?

I'm not an expert in language implementations (so take this with a grain of salt), but I think one of the biggest costs is unwinding the stack and storing it for the stack trace. I suspect this happens only when the exception is thrown (but I don't know), and if so, this would be decently sized hidden cost every time an exception is thrown... so it's not like you are just jumping from one place in the code to another, there is a lot going on.

I don't think it's a problem as long as you are using exceptions for EXCEPTIONAL behavior (so not your typical, expected path through the program).

C# performance cost of exceptions

Use Dictionary.TryGetValue to avoid exceptions in your example code at all. The most expensive part is the try .. catch.

If you cannot get away from exceptions then you should use a different pattern to perform actions inside a loop.

Instead of

for ( i = 0; i < 100; i++ )
try
{
DoSomethingThatMaybeThrowException();
}
catch (Exception)
{
// igrnore or handle
}

which will set up the try .. catch for every step whether an exception has raised or not, use

int i = 0;
while ( i < 100 )
try
{
while( i < 100 )
{
DoSomethingThatMaybeThrowException();
i++;
}
}
catch ( Exception )
{
// ignore or handle
i++;
}

which will only set up a new try .. catch when an exception was thrown.

BTW

I cannot reproduce that massive slowdown of your code as you describe. .net fiddle

try catch for performance c#

The link I provided in the above comment shows a description of why you shouldn't ever use a try-catch when an if-statement would prevent the exception from being thrown, but in the interest of showing performance in terms of actual numbers, I wrote this quick little test program.

Stopwatch watch = new Stopwatch();

int[] testArray = new int[] { 1, 2, 3, 4, 5 };
int? test = null;

watch.Start();
for (int i = 0; i < 10000; i++)
{
try
{
testArray[(int)test] = 0;
}
catch { }
}
watch.Stop();

Console.WriteLine("try-catch result:");
Console.WriteLine(watch.Elapsed);
Console.WriteLine();

watch.Restart();
for (int i = 0; i < 10000; i++)
{
if (test != null)
testArray[(int)test] = 0;
}
watch.Stop();

Console.WriteLine("if-statement result:");
Console.WriteLine(watch.Elapsed);

The result of the program is this:

try-catch result:
00:00:32.6764911

if-statement result:
00:00:00.0001047

As you can see, the try-catch approach introduces significant overhead when an exception gets caught, taking over 30 seconds to complete 10,000 cycles on my machine. The if-statement, on the other hand, runs so fast that it is basically instantaneous. Compared to the try-catch, this is a performance improvement in the neighborhood of 3,000,000%.

(This isn't a rigorous benchmark, and there are ways to write it and run it differently to get more precise numbers, but this should give you a good idea of just how much more efficient it is to use an if-statement over a try-catch whenever possible.)

Overhead of try/finally in C#?

Why not look at what you actually get?

Here is a simple chunk of code in C#:

    static void Main(string[] args)
{
int i = 0;
try
{
i = 1;
Console.WriteLine(i);
return;
}
finally
{
Console.WriteLine("finally.");
}
}

And here is the resulting IL in the debug build:

.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
.maxstack 1
.locals init ([0] int32 i)
L_0000: nop
L_0001: ldc.i4.0
L_0002: stloc.0
L_0003: nop
L_0004: ldc.i4.1
L_0005: stloc.0
L_0006: ldloc.0 // here's the WriteLine of i
L_0007: call void [mscorlib]System.Console::WriteLine(int32)
L_000c: nop
L_000d: leave.s L_001d // this is the flavor of branch that triggers finally
L_000f: nop
L_0010: ldstr "finally."
L_0015: call void [mscorlib]System.Console::WriteLine(string)
L_001a: nop
L_001b: nop
L_001c: endfinally
L_001d: nop
L_001e: ret
.try L_0003 to L_000f finally handler L_000f to L_001d
}

and here's the assembly generated by the JIT when running in debug:

00000000  push        ebp 
00000001 mov ebp,esp
00000003 push edi
00000004 push esi
00000005 push ebx
00000006 sub esp,34h
00000009 mov esi,ecx
0000000b lea edi,[ebp-38h]
0000000e mov ecx,0Bh
00000013 xor eax,eax
00000015 rep stos dword ptr es:[edi]
00000017 mov ecx,esi
00000019 xor eax,eax
0000001b mov dword ptr [ebp-1Ch],eax
0000001e mov dword ptr [ebp-3Ch],ecx
00000021 cmp dword ptr ds:[00288D34h],0
00000028 je 0000002F
0000002a call 59439E21
0000002f xor edx,edx
00000031 mov dword ptr [ebp-40h],edx
00000034 nop
int i = 0;
00000035 xor edx,edx
00000037 mov dword ptr [ebp-40h],edx
try
{
0000003a nop
i = 1;
0000003b mov dword ptr [ebp-40h],1
Console.WriteLine(i);
00000042 mov ecx,dword ptr [ebp-40h]
00000045 call 58DB2EA0
0000004a nop
return;
0000004b nop
0000004c mov dword ptr [ebp-20h],0
00000053 mov dword ptr [ebp-1Ch],0FCh
0000005a push 4E1584h
0000005f jmp 00000061
}
finally
{
00000061 nop
Console.WriteLine("finally.");
00000062 mov ecx,dword ptr ds:[036E2088h]
00000068 call 58DB2DB4
0000006d nop
}
0000006e nop
0000006f pop eax
00000070 jmp eax
00000072 nop
}
00000073 nop
00000074 lea esp,[ebp-0Ch]
00000077 pop ebx
00000078 pop esi
00000079 pop edi
0000007a pop ebp
0000007b ret
0000007c mov dword ptr [ebp-1Ch],0
00000083 jmp 00000072

Now, if I comment out the try and finally and the return, I get nearly identical assembly from the JIT. The differences you'll see are a jump into the finally block and some code to figure out where to go after the finally is executed. So you're talking about TINY differences. In release, the jump into the finally will get optimized out - braces are nop instructions, so this would become a jump to the next instruction, which is also a nop - that's an easy peephole optimization. The pop eax and then jmp eax is similarly cheap.

    {
00000000 push ebp
00000001 mov ebp,esp
00000003 push edi
00000004 push esi
00000005 push ebx
00000006 sub esp,34h
00000009 mov esi,ecx
0000000b lea edi,[ebp-38h]
0000000e mov ecx,0Bh
00000013 xor eax,eax
00000015 rep stos dword ptr es:[edi]
00000017 mov ecx,esi
00000019 xor eax,eax
0000001b mov dword ptr [ebp-1Ch],eax
0000001e mov dword ptr [ebp-3Ch],ecx
00000021 cmp dword ptr ds:[00198D34h],0
00000028 je 0000002F
0000002a call 59549E21
0000002f xor edx,edx
00000031 mov dword ptr [ebp-40h],edx
00000034 nop
int i = 0;
00000035 xor edx,edx
00000037 mov dword ptr [ebp-40h],edx
//try
//{
i = 1;
0000003a mov dword ptr [ebp-40h],1
Console.WriteLine(i);
00000041 mov ecx,dword ptr [ebp-40h]
00000044 call 58EC2EA0
00000049 nop
// return;
//}
//finally
//{
Console.WriteLine("finally.");
0000004a mov ecx,dword ptr ds:[034C2088h]
00000050 call 58EC2DB4
00000055 nop
//}
}
00000056 nop
00000057 lea esp,[ebp-0Ch]
0000005a pop ebx
0000005b pop esi
0000005c pop edi
0000005d pop ebp
0000005e ret

So you're talking very, very tiny costs for try/finally. There are very few problem domains where this matters. If you're doing something like memcpy and put a try/finally around each byte being copied and then proceed to copy hundreds of MB of data, I could see that being an issue, but in most usage? Negligible.

Do try/catch blocks hurt performance when exceptions are not thrown?

Check it.

static public void Main(string[] args)
{
Stopwatch w = new Stopwatch();
double d = 0;

w.Start();

for (int i = 0; i < 10000000; i++)
{
try
{
d = Math.Sin(1);
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}
}

w.Stop();
Console.WriteLine(w.Elapsed);
w.Reset();
w.Start();

for (int i = 0; i < 10000000; i++)
{
d = Math.Sin(1);
}

w.Stop();
Console.WriteLine(w.Elapsed);
}

Output:

00:00:00.4269033  // with try/catch
00:00:00.4260383 // without.

In milliseconds:

449
416

New code:

for (int j = 0; j < 10; j++)
{
Stopwatch w = new Stopwatch();
double d = 0;
w.Start();

for (int i = 0; i < 10000000; i++)
{
try
{
d = Math.Sin(d);
}

catch (Exception ex)
{
Console.WriteLine(ex.ToString());
}

finally
{
d = Math.Sin(d);
}
}

w.Stop();
Console.Write(" try/catch/finally: ");
Console.WriteLine(w.ElapsedMilliseconds);
w.Reset();
d = 0;
w.Start();

for (int i = 0; i < 10000000; i++)
{
d = Math.Sin(d);
d = Math.Sin(d);
}

w.Stop();
Console.Write("No try/catch/finally: ");
Console.WriteLine(w.ElapsedMilliseconds);
Console.WriteLine();
}

New results:

   try/catch/finally: 382
No try/catch/finally: 332

try/catch/finally: 375
No try/catch/finally: 332

try/catch/finally: 376
No try/catch/finally: 333

try/catch/finally: 375
No try/catch/finally: 330

try/catch/finally: 373
No try/catch/finally: 329

try/catch/finally: 373
No try/catch/finally: 330

try/catch/finally: 373
No try/catch/finally: 352

try/catch/finally: 374
No try/catch/finally: 331

try/catch/finally: 380
No try/catch/finally: 329

try/catch/finally: 374
No try/catch/finally: 334

Try-Catch vs If performance in C#

Exceptions are not made to control the flow of your code. They are made to treat "exceptional" circumstances, e.g. connection issues or invalid file formats.

If you want to control your code flow, you should use conditional statements like if, else and switch.

The performance of exceptions is generally bad compared to some simple if-statement, but there are also situations when exception-handling might be even faster than checking data for validity manually, especially if you don't know how to do it fast.
There might also be plenty of situations where you "know" an exception could be raised, but you simply trust the data - e.g. checking your own settings file for valid xml format.

Most of the time, you want to use Exceptions, to have error information later, e.g. line number of the error in the xml file and to recover your application in some way (e.g. reconnect to a socket).

You can not give a general statement about the performance of exceptions, but when you can avoid them, you should.
They are made for exceptions as their name already tells.

A small example where you can potentially avoid exceptions:

try
{
LoginUser("Fooooo", "Bar");
} catch(InvalidPasswordException e) {
MessageBox.Show(e.Message);
}

private static void LoginUser(string pUsername, string pPassword)
{
if (pUsername != "Foo" || pPassword != "Bar")
throw new InvalidPasswordException("Invalid username and/or password");

GrantAccess(pUsername);
}

Instead of throwing the exception you could also just return a boolean:

if (!LoginUser("Fooooo", "Bar"))
{
MessageBox.Show("Invalid username and/or password");
}

private static bool LoginUser(string pUsername, string pPassword)
{
if (pUsername != "Foo" || pPassword != "Bar")
return false;

GrantAccess(pUsername);
return true;
}

Performance-Test: 10000 attempts with false credentials:

throwing Exception (without displaying the messagebox): 181990454 ticks

returning boolean: 644 ticks

And we are only 1 layer into the application, so there is not much stacktrace to be generated. I guess you can see and especially feel the difference.

Performance of returning from a Try block

If there is a performance hit, it's tiny. It's certainly nothing like the same as catching the exception. (And even that's not as bad as many people think.)

As far as I'm aware, the performance of returning from a try block is negligible. The chance of it being significant in your app is essentially 0. Just write the most readable code you can, and then benchmark/profile your app - that will be a much better way to get good performance than trying to second guess this sort of thing.



Related Topics



Leave a reply



Submit