exception比返回值贵多少钱?

是否可以使用返回值和exception更改此代码:

public Foo Bar(Bar b) { if(b.Success) { return b; } else { throw n.Exception; } } 

对此,它会为成功和失败抛出单独的例外

 public Foo Bar(Bar b) { throw b.Success ? new BarException(b) : new FooException(); } try { Bar(b) } catch(BarException bex) { return ex.Bar; } catch(FooException fex) { Console.WriteLine(fex.Message); } 

抛出exception肯定比返回值更昂贵。 但就原始成本而言,很难说exception是多么昂贵。

在决定返回值与exception时,您应始终考虑以下规则。

仅在特殊情况下使用例外

它们不应该用于一般控制流程。

使用下面的代码,测试显示,没有exception的调用+返回每次迭代大约需要1.6微秒,而exception(throw plus catch)每次增加大约4000微秒。(!)

 public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void button1_Click(object sender, EventArgs e) { DateTime start = DateTime.Now; bool PreCheck = chkPrecheck.Checked; bool NoThrow = chkNoThrow.Checked; int divisor = (chkZero.Checked ? 0 : 1); int Iterations = Convert.ToInt32(txtIterations.Text); int i = 0; ExceptionTest x = new ExceptionTest(); int r = -2; int stat = 0; for(i=0; i < Iterations; i++) { try { r = x.TryDivide(divisor, PreCheck, NoThrow); } catch { stat = -3; } } DateTime stop = DateTime.Now; TimeSpan elapsed = stop - start; txtTime.Text = elapsed.TotalMilliseconds.ToString(); txtReturn.Text = r.ToString(); txtStatus.Text = stat.ToString(); } } class ExceptionTest { public int TryDivide(int quotient, bool precheck, bool nothrow) { if (precheck) { if (quotient == 0) { if (nothrow) { return -9; } else { throw new DivideByZeroException(); } } } else { try { int a; a = 1 / quotient; return a; } catch { if (nothrow) { return -9; } else { throw; } } } return -1; } } 

所以,是的,例外是非常昂贵的。

在有人说出来之前,我在发布模式下测试了这个,而不仅仅是调试模式。 亲自尝试一下代码,看看你是否得到了明显不同的结果。

exception有两个成本:在exception基础结构中预热页面 – 如果没有进入内存然后进入CPU缓存 – 并且每次抛出成本来收集exception堆栈,搜索exception处理程序,可能调用exceptionfilter,展开堆栈,调用终结块 – 运行时,设计,不优化的所有操作。

因此,衡量抛出exception的成本可能会产生误导。 如果你编写一个迭代抛出并捕获exception的循环,抛出站点和catch站点之间没有大量工作,那么成本就不会那么大。 但是,这是因为它正在摊还exception的预热成本,而且成本更难以衡量。

当然,如果一个人的主要经验是调试器下的程序抛出的exception,那么例外并不会花费任何费用。 但它们确实需要成本,特别是设计库是可取的,这样可以在必要时优化exception。

你可以在这个问题的答案中找到很多有用的信息,包括一个45 up-votes的答案.net例外有多慢?

使用错误返回将比exception更昂贵 – 只要一段代码忘记检查错误返回,或者无法传播它。

尽管如此,请确保不要使用控制流的exception – 仅使用它们来表示出现问题。

我在找到支持它的任何文件时遇到了麻烦,但请记住,当你抛出exception时,C#必须从你调用它的位置生成一个堆栈跟踪。 堆栈跟踪(和一般的reflection)远非免费。

在最近的一些实际工作性能分析中,我们发现低端机器上的大量例外对应用程序性能有着至关重要的影响,因此我们花费了几周的时间来完成并调整代码而不是抛出那么多。

当我说一个关键效应时,应用程序正在使用的单核CPU核心上将双核CPU高达95%。

您应该首选exception而不是错误代码,以及错误条件,但不要使用exception来处理正常的程序流。

与正常工作流程相比,exception是非常繁重的工作,我已经看到使用try-catch-block导致应用程序性能大幅下降。

抛出exception是一种相对便宜的操作。 由于必须发现捕获处理程序,执行catch处理程序中的代码,查找finally块,执行finally块中的代码,然后返回到原始调用者,必须发生堆栈遍历才能捕获它们。

强烈建议您不要对控制流使用exception。 从“时间和材料”的角度来看,使用返回代码来指示错误会变得昂贵,因为它最终会产生维护成本。

除此之外,你的两个例子不匹配,甚至没有效果。 因为你是返回b ,它是Bar类型,你的第一个方法应该是:

 public Bar Foo(Bar b) { if(b.Success) { return b; } else { throw n.Exception; } } 

可以改写为:

 public Bar Foo(Bar b) { if (!b.Success) throw n.Exception; return b; } 

一般来说,由于捕获exception的昂贵性质,我已经避免了这种情况。 如果它不是经常发生的事情,那可能不会太糟糕。

但是,为什么不只返回null? 然后就变成了这个:

 public Foo Bar(Bar b) { if(b.Success) { return b; } else { return null; } } 

然后,无论何时调用Bar(),您只需检查以确保在使用该值之前返回的值不为null。 这是一个便宜得多的操作。 我认为这是一个很好的做法,因为这是微软在许多.NET的内置函数中使用的技术。

我看到许多不同的系统,其中exception被认为是软件问题的指示,并且还意味着提供有关导致它的事件的信息。 这对系统来说总是很重要。 然而,有些系统exception并不例外,因为语言本身使用相同或类似的方法从常规等返回。因此,它归结为exception如何嵌入语言和系统中。 我在java和我现在工作的专有系统中进行了测量,结果与预期一致 – 例外,例外(20-25)%更贵。

这不一定是规则。 我想知道python如何站在这上面。 我不再进行任何python开发了,所以我不打算进行调查。

作为一个可能有趣的轶事证据,我认为:在几年前我工作的专有系统中,非协作使用协议违规的例外导致严重的问题和我们的一个生产系统的中断。 例外用于表示从外部收到的消息中缺少或损坏的必填字段。 一切都很好,直到一个阳光灿烂的日子,一些不太熟练的公司生产了一个节点,在投入运行时,造成了很多麻烦。 必须删除例外,因为我们无法处理来自故障节点的低水平信令。 故障确实也在我们这边 – 而不是按照协议规范描述如何处理格式错误的消息(忽略并执行信号故障计数器)我们试图检测和调试外部节点中的软件故障。 如果例外情况较便宜,那就不会那么重要了。

事实上,在测试安全性的这些天里,我总是有一个TC或少数确实如此 – 产生大量的协议违规情况。 如果开发人员使用exception来处理那些,那么系统可以很容易地陷入困境。 当这一次失败后,我将再次开始测量差异….