为什么C#没有轻量级异常?

时间:2012-12-08 19:32:55

标签: c# .net exception error-handling

often said由于bad performance,您不应该使用例外进行常规错误处理。我的猜测是,糟糕的性能是由于必须实例化一个新的异常对象,生成一个堆栈跟踪等等。那么为什么没有轻量级异常?像这样的代码在逻辑上是合理的:

string ageDescription = "Five years old";
try {
    int age = int.Parse(ageDescription);
}
catch (Exception) {
    // Couldn't parse age; handle parse failure
}

然而,我们建议使用TryParse来避免异常的开销。但是,如果异常只是在线程启动时初始化的静态对象,则抛出异常所需的所有代码都需要设置错误代码编号,也可能是错误字符串。没有堆栈跟踪,没有新的对象实例化。它将是一个“轻量级异常”,因此使用异常的开销将大大减少。为什么我们没有这样的轻量级例外?

6 个答案:

答案 0 :(得分:4)

异常对象实例化是整个案例中最小的问题。真正的性能杀手是控制流必须停止执行你的程序,并且必须查找可以捕获抛出异常的可能处理程序(catch块)的调用堆栈,然后它必须执行正确的(和它们的finally块) ,当被告知时重新抛出异常,然后继续在正确的位置执行程序,即在最后一个处理程序之后。你对“轻量级”异常的想法不会改变这一点,它甚至会减慢线程的创建速度,因为它必须创建和存储异常对象,并且会阻止按类型进行异常过滤,这现在是可能的。

通过使用TryParse,您可以通过一个简单的条件子句来避免这一切,实际上您可以编写更少的代码,并且更容易阅读和推理。

例外情况适用于特殊情况,在这种情况下,它们为日志/调试器提供了大量有用的信息。

答案 1 :(得分:4)

性能提升不仅仅是因为您正在创建一个新的Exception对象。其中很多都与发生异常时需要完成的堆栈的条件展开有关。

例如,考虑一下当您拥有捕获不同类型异常的异常处理程序时必须完成的工作。在堆栈中的每个点,当它从被调用者解调到调用者时,语言必须进行类型检查,不仅要查看是否可以处理异常,还要查看最合适的处理程序是什么。这本身就是一笔巨大的开销。

如果你真的想要轻量级,你应该从你的函数返回一个结果 - 这就是Int32.TryParse()所做的。没有堆栈展开,没有类型检查,只是一个可以轻松优化的简单条件。

编辑:有一点值得注意的是C#是在Java之后创建的。 Java有一些有趣的结构,它们导致异常处理比我们在C#中看到的更复杂,即checked exceptionsthrows关键字。一种有趣的读物。我(个人)很高兴C#没有包含这个“功能”。我的猜测是他们将他们的异常处理程序分成两部分来提升性能。在现实世界中,据我所知,很多开发人员最终都在其函数声明中指定了throws exception

答案 2 :(得分:3)

您应该在案件中使用int.TryParse。并且测试某些条件然后抛出并捕获异常更快更可读。在特殊情况下使用例外而不是常规验证。

答案 3 :(得分:3)

异常的问题不仅仅是生成异常本身,老实说甚至不是最耗时的部分。当你抛出异常时(在创建它之后)它需要解开遍历每个范围级别的堆栈,确定该范围是否是捕获此异常的try / catch块,更新异常表明它经过堆栈的那一部分,然后拆掉堆栈的那一部分。然后当然可能需要执行所有finally块。使Exception本身存储更少的信息并不会真正简化任何信息。

答案 4 :(得分:2)

因为“重量级”例外提供的效用特别(哈哈)有用。我无法告诉你我多久都希望能够在C盘中转储类似堆栈跟踪的东西,而不必让人们抽出调试器。

在事实之后(即在按需捕获异常之后)生成堆栈跟踪之类的东西是不可行的,因为一旦捕获到异常,堆栈就已经解开 - 信息消失了。您需要有关故障点的信息;所以必须在失败时收集数据。

至于“新对象实例化” - 与其他昂贵的异常功能(展开堆栈,堆栈跟踪,多个功能退出点等)相比,它是如此便宜,这是不值得担心的。 / p>

答案 5 :(得分:1)

由于性能原因,建议您不要使用TryParse而不是Parse。如果解析有可能失败(因为它是用户生成的输入),那么解析失败不是例外,这是预期的。顾名思义,例外是针对特殊情况。对于应该早些时候被抓住的东西,但不是,出乎意料的是你无法继续。

如果一个函数需要一个对象而不是传递null,那么由该方法的设计者决定在这种情况下正确的做法。如果参数是默认值的可选覆盖,则程序将继续并使用默认值或忽略该参数。但除此之外,程序应该简单地抛出ArgumentNullException

在决定是否使用例外时,性能不应该是一个考虑因素。这是一个意图和目的的问题。它们甚至不是那么慢,确定它们比添加两个整数慢很多倍,但我仍然可以在我老化的Core 2 Duo上每秒抛出50,000个例外。如果异常的使用成为瓶颈,那么你就不会以正确的方式使用它们。