Exception Performance
We've all heard it many times: Exceptions are slow. The problem with this, is developers can read this and adopt bad practices under the assumption that their slowness eliminates their usefulness. Like anything else related to performance, it's best to understand when to use them, and when they may actually impact your code.
Exceptions are just a contract class, so they aren't inherently slow. The 'slow' bit that is often brought up has to do with unwinding the stack during the raising of an exception. BUT for my own curiosity, I created a full-fledged test of a scenario. (Code pasted below).
Throwing 100,000 exceptions takes just under a second on my machine (Keeping in mind that the server machines are actually faster). Each exception throwing/catching takes roughly 0.000009 seconds. This method is maybe called a handful of times a second (Now, that's a complete over-estimate, under most normal web use-cases), which means we're saving a very small amount of time by omitting their use.
Now, to defeat the insert very small number here affect, I also ran the same performance test against a common logger (NLog). To log 100,000 messages took on average 8-9 seconds. Taking 0.0001 seconds each. Now, just because this is around 10x slower than throwing an exception doesn't mean we should stop logging. We all know we need this data in order to do our jobs well, and make informed decisions impacting our technology and how it affects customers.
So, what's the moral of my long story? We should focus on using the technology at our disposal in two critical ways:
- Making sure it follows conventions setup by guiding parties (Microsoft/MSDN, Your Company and Teams)
- Remember that 'performance' is relative.
It's one thing if the method in question was being called 100,000 times per second. That would mean we'd need to super-optimize it and take out tiny little bits that affect performance. But in normal cases it won't be called that often. Also, keep in mind that exceptions are being thrown during an EXCEPTIONAL case. That is, they're should not be thrown every time a method is called, but rather when something goes wrong. And honestly, at the point where something is going wrong as critical as warrenting an exception, the performance of throwing an exception is usually the least of my worries.
Logging Benchmark
(Using a standard setup of NLog streaming to file and output)
var sw = new Stopwatch();
const int ITERATIONS = 100000;
sw.Start();
for (int i = 0; i < ITERATIONS; ++i)
{
_logger.Log(new LogEventInfo(LogLevel.Debug, _logger.Name, "Test"));
}
sw.Stop();
Exception Benchmark Code
private class InnerClass
{
public void ThrowException()
{
throw new Exception("Bla");
}
}
private class TestClass
{
private readonly InnerClass _inner = new InnerClass();
public void DO()
{
_inner.ThrowException();
}
}
static void Main()
{
var sw = new Stopwatch();
const int ITERATIONS = 100000;
var test = new TestClass();
sw.Start();
for (int i=0; i<ITERATIONS; ++i)
{
try
{
test.DO();
}
catch(Exception e)
{
}
}
sw.Stop();
Console.WriteLine("Total {0}ms, taking {1}ms/each", sw.ElapsedMilliseconds, sw.ElapsedMilliseconds / (double)ITERATIONS);
}