Yes, try/catch
will "hurt" performance (everything is relative). Not much in terms of wasted CPU
cycles, but there are other important aspects to consider:
- Code size
- Method inlining
Benchmark
First, let's check the speed using some sophisticated tools (i.e. BenchmarkDotNet). Compiled as Release (AnyCPU)
, run on x64
machine. I would say there is no difference, even though the test will indeed tell us that NoTryCatch()
is a tiny, tiny bit faster:
| Method | N | Mean | Error | StdDev |
|------------------ |---- |---------:|----------:|----------:|
| NoTryCatch | 0.5 | 3.770 ns | 0.0492 ns | 0.0411 ns |
| WithTryCatch | 0.5 | 4.060 ns | 0.0410 ns | 0.0384 ns |
| WithTryCatchThrow | 0.5 | 3.924 ns | 0.0994 ns | 0.0881 ns |
Analysis
Some additional notes.
| Method | Code size | Inlineable |
|------------------ |---------- |-----------:|
| NoTryCatch | 12 | yes |
| WithTryCatch | 18 | ? |
| WithTryCatchThrow | 18 | no |
Code size NoTryCatch()
yields 12 bytes in code whereas a try/catch adds another 6 bytes. Also, whenever writing a try/catch
you will most likely have one or more throw new Exception("Message", ex)
statements, further "bloating" the code.
The most important thing here though is code inlining. In .NET
the mere existence of the throw
keyword implies that the method will never be inlined by the compiler (implying slower code, but also less footprint). I recently tested this fact thoroughly, so it still seems valid in .NET Core
. Not sure if try/catch
follows the same rule. TODO: Verify!
Complete test code
using System;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;
namespace TryCatchPerformance
{
public class TryCatch
{
[Params(0.5)]
public double N { get; set; }
[Benchmark]
public void NoTryCatch() => Math.Sin(N);
[Benchmark]
public void WithTryCatch()
{
try
{
Math.Sin(N);
}
catch
{
}
}
[Benchmark]
public void WithTryCatchThrow()
{
try
{
Math.Sin(N);
}
catch (Exception ex)
{
throw;
}
}
}
class Program
{
static void Main(string[] args)
{
var summary = BenchmarkRunner.Run<TryCatch>();
}
}
}
try
/catch
block is bad - and the answer was "No, it's great - usetry
/catch
!". You definitely don't want these ugly error messages being displayed to your users. – Wingover