C#中的exception有多昂贵?

C#中的exception有多昂贵? 只要堆栈不深,似乎并不是非常昂贵; 但是我读到了相互矛盾的报道。

有没有被反驳的确切的报告?

2006年1月,Jon Skeet 在.NET中写了Exceptions and Performance

哪些更新了exception和性能重做(谢谢@Gulzar)

Rico Mariani在.NET Exceptions的真实代价中提到的 – 解决scheme


另请参阅:Krzysztof Cwalina – devise指南更新:exception投掷

我想我是在阵营中,如果性能exception会影响你的应用程序,那么你就会抛弃太多的方法。 例外情况应该是例外的情况,而不是常规的error handling。

也就是说,我记得如何处理exception,基本上是find一个匹配抛出exceptiontypes的catch语句。 所以,performance会受到多大的影响,你是多么深的抓住了你有多lesscatch语句。

读过这些例外情况,在性能方面是昂贵的,我把一个简单的测量程序放在一起,这与Jon Skeet几年前发表的非常相似。 我在这里提到这主要是为了提供更新的数字。

程序在29914毫秒的时间内处理了100万个例外, 每毫秒达到33个例外 。 这足以使例外成为大多数情况下返回代码的可行select。

但请注意,使用返回代码而不是exception,相同的程序运行时间less于1毫秒,这意味着exception至less比返回代码慢30,000倍 。 正如Rico Mariani所强调的,这些数字也是最小的数字。 在实践中,抛出和捕捉exception将需要更多的时间。

在Intel Core2 Duo T8100 @ 2.1 GHz的笔记本电脑上testing,发布版本不会在debugging器下运行 (这会让速度变慢)。

这是我的testing代码:

static void Main(string[] args) { int iterations = 1000000; Console.WriteLine("Starting " + iterations.ToString() + " iterations...\n"); var stopwatch = new Stopwatch(); // Test exceptions stopwatch.Reset(); stopwatch.Start(); for (int i = 1; i <= iterations; i++) { try { TestExceptions(); } catch (Exception) { // Do nothing } } stopwatch.Stop(); Console.WriteLine("Exceptions: " + stopwatch.ElapsedMilliseconds.ToString() + " ms"); // Test return codes stopwatch.Reset(); stopwatch.Start(); int retcode; for (int i = 1; i <= iterations; i++) { retcode = TestReturnCodes(); if (retcode == 1) { // Do nothing } } stopwatch.Stop(); Console.WriteLine("Return codes: " + stopwatch.ElapsedMilliseconds.ToString() + " ms"); Console.WriteLine("\nFinished."); Console.ReadKey(); } static void TestExceptions() { throw new Exception("Failed"); } static int TestReturnCodes() { return 1; } 

C#中的Barebonesexception对象相当轻量级; 它通常是封装一个InnerException的能力,当对象树变得太深的时候它会变得沉重。

至于一个明确的报告,我不知道任何,虽然一个粗略的dotTraceconfiguration文件(或任何其他分析器)的内存消耗和速度将相当容易做到。

就我而言,例外情况非常昂贵。 我重写了这个:

 public BlockTemplate this[int x,int y, int z] { get { try { return Data.BlockTemplate[World[Center.X + x, Center.Y + y, Center.Z + z]]; } catch(IndexOutOfRangeException e) { return Data.BlockTemplate[BlockType.Air]; } } } 

进入这个:

 public BlockTemplate this[int x,int y, int z] { get { int ix = Center.X + x; int iy = Center.Y + y; int iz = Center.Z + z; if (ix < 0 || ix >= World.GetLength(0) || iy < 0 || iy >= World.GetLength(1) || iz < 0 || iz >= World.GetLength(2)) return Data.BlockTemplate[BlockType.Air]; return Data.BlockTemplate[World[ix, iy, iz]]; } } 

并注意到大约30秒的好速度增加。 这个函数在启动时被调用至less32K次。 代码不清楚意图是什么,但节省的成本是巨大的。

性能受到exception的影响似乎是在生成exception对象的时候(尽pipe太小而不能引起90%的时间关注)。 因此,build议您对代码进行概要分析 – 如果exception导致性能下降,则编写一个不使用exception的新高性能方法。 (一个想到的例子是(TryParse被引入来克服使用exception的Parse的性能问题)

话虽如此,在大多数情况下,例外情况在大多数情况下不会导致显着的性能命中 – 所以MSdevise指南是通过抛出exception来报告失败

我做了我自己的测量,以查明exception含义是多么严重。 我没有尝试去衡量投掷/捕捉exception的绝对时间。 我最感兴趣的是如果在每次传递中抛出一个exception,循环会变得多慢。 测量代码看起来像这样

  for(; ; ) { iValue = Level1(iValue); lCounter += 1; if(DateTime.Now >= sFinish) break; } 

VS

  for(; ; ) { try { iValue = Level3Throw(iValue); } catch(InvalidOperationException) { iValue += 3; } lCounter += 1; if(DateTime.Now >= sFinish) break; } 

差别是20倍。 第二个片段慢了20倍。