一个常见的说法是,异常在被捕获时是昂贵的——而不是被抛出。这是因为大部分异常元数据收集(例如获取堆栈跟踪等)仅真正发生在 try-catch 端(而不是 throw 端)。
展开堆栈实际上非常快——CLR 沿着调用堆栈向上走,只注意它找到的 finally 块;在纯 try-finally 块中,运行时绝不会尝试“完成”异常(它是元数据等)。
据我所知,任何带有过滤器的 try-catch(例如“catch (FooException) {}”)都一样昂贵 - 即使它们对异常不做任何事情。
我敢说一个方法(称为CatchesAndRethrows)具有以下块:
try
{
ThrowsAnException();
}
catch
{
throw;
}
可能会导致方法中的堆栈遍历更快 - 例如:
try
{
CatchesAndRethrows();
}
catch (Exception ex) // The runtime has already done most of the work.
{
// Some fancy logic
}
一些数字:
With: 0.13905ms
Without: 0.096ms
Percent difference: 144%
这是我运行的基准测试(记住,发布模式 - 无需调试即可运行):
static void Main(string[] args)
{
Stopwatch withCatch = new Stopwatch();
Stopwatch withoutCatch = new Stopwatch();
int iterations = 20000;
for (int i = 0; i < iterations; i++)
{
if (i % 100 == 0)
{
Console.Write("{0}%", 100 * i / iterations);
Console.CursorLeft = 0;
Console.CursorTop = 0;
}
CatchIt(withCatch, withoutCatch);
}
Console.WriteLine("With: {0}ms", ((float)(withCatch.ElapsedMilliseconds)) / iterations);
Console.WriteLine("Without: {0}ms", ((float)(withoutCatch.ElapsedMilliseconds)) / iterations);
Console.WriteLine("Percent difference: {0}%", 100 * withCatch.ElapsedMilliseconds / withoutCatch.ElapsedMilliseconds);
Console.ReadKey(true);
}
static void CatchIt(Stopwatch withCatch, Stopwatch withoutCatch)
{
withCatch.Start();
try
{
FinallyIt(withoutCatch);
}
catch
{
}
withCatch.Stop();
}
static void FinallyIt(Stopwatch withoutCatch)
{
try
{
withoutCatch.Start();
ThrowIt(withoutCatch);
}
finally
{
withoutCatch.Stop();
}
}
private static void ThrowIt(Stopwatch withoutCatch)
{
throw new NotImplementedException();
}