How Slow Are .Net Exceptions

How slow are .NET exceptions?

I'm on the "not slow" side - or more precisely "not slow enough to make it worth avoiding them in normal use". I've written two short articles about this. There are criticisms of the benchmark aspect, which are mostly down to "in real life there'd be more stack to go through, so you'd blow the cache etc" - but using error codes to work your way up the stack would also blow the cache, so I don't see that as a particularly good argument.

Just to make it clear - I don't support using exceptions where they're not logical. For instance, int.TryParse is entirely appropriate for converting data from a user. It's inappropriate when reading a machine-generated file, where failure means "The file isn't in the format it's meant to be, I really don't want to try to handle this as I don't know what else might be wrong."

When using exceptions in "only reasonable circumstances" I've never seen an application whose performance was significantly impaired by exceptions. Basically, exceptions shouldn't happen often unless you've got significant correctness issues, and if you've got significant correctness issues then performance isn't the biggest problem you face.

Why is throwing exceptions so slow?

Exception handling requires some complexity and "magic". Seconding @Joni's response a major cost is gathering the stack trace. When an exception is thrown, the run time has to walk down the stack's activation records looking for a compatible exception handler, executing finally blocks each step of the way. All this has to occur at run time; it can't be fixed up by the compiler. In languages like C++ destructors have to be executed.

Exception processing is essentially an out of band "exceptional" processing mode. Things that speed up normal execution such as caching don't work as well. (I would imagine locality-of-reference is a lot worse here). This processing could be optimized, but since exc handing is supposed to be "special" it's given less attention.

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

.NET Exception And Performance

Well, because it does something. Doing anything takes time.

Throwing an exception creates an object, obtains a copy of the stack, walks the stack up to two times, and perhaps marshals across domains. Doing stuff takes time. In an ideal world it will also be the branch that wasn't predicted as being taken (because it should be the branch that was less likely) though I've no idea if that's the case or not. It's also particularly likely to lead to cases where the caches are being refilled because control has moved to somewhere "far away".

All that said though, exceptions aren't particularly slow except when being run in a debugger (which for obvious reasons does more work again when an exception is thrown). It's slow enough that doing try-and-catch in a loop where doing test-and-try or tryparse-and-report makes more sense is a bad idea, but these fall into the category of good micro-optimisations ("micro-optimisation" is often used as a slur, but when the approach that's semantically clearer is also slightly more performant then it's a good thing for the reason of that clarity - it's when we make things less clear and semantically sensible for the sake of a few cycles that "micro-optimisation" becomes a negative).

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

Exception handling. How long does catch take?

Exceptions are slower than all other program flow but not to the extent they should be avoided for performance reasons. However, they are not meant to be used for program flow. In your situation, you have a very valid alternative that is better than using exceptions. When you can predict a situation and handle it appropriately without exceptions, always do that. Also, don't use exceptions in normal program flow as a convenience.

Use exceptions when you have an unanticipated exceptional situation you can't handle directly.



Related Topics



Leave a reply



Submit