.NET异常有多慢?

151
我不想讨论何时抛出异常和何时不抛出异常的问题,我希望解决一个简单的问题。99%的时间里,不抛出异常的理由是它们很慢,而另一方则声称(通过基准测试)速度不是问题。我已经阅读了许多关于这个问题的博客、文章和帖子,那么到底是哪种情况呢?
答案中提供了一些链接:SkeetMarianiBrumme

14
有谎言,该死的谎言和基准测试。 :) - gbjbaanb
1
不幸的是,这里有几个得票很高的答案忽略了问题所问的“异常有多慢?”并明确要求避免讨论何时使用它们的话题。对于实际提出的问题,一个简单的答案是......在Windows CLR上,异常比返回值慢750倍。 - David Jeske
14个回答

1

在发布模式下,开销是最小的。

除非你要以递归方式使用异常来进行流程控制(例如,非局部退出),否则我怀疑你不会注意到差异。


1

我认为你已经回答了自己的问题。你和几乎所有理解它们的人都知道它们慢。这是一个100%的事实,但正如许多其他人指出的那样,上下文才是100%的关键,决定何时使用它们。编写非服务器应用程序?你永远不会注意到任何区别。编写公共API的网站,其中格式错误的客户端请求可能在后端触发异常?这是一种灾难性的情况,其数量级乘以每秒的请求数。后端被钉住的次数比杂货店里的小马还要多。然而,问题在于BCL/其他库会抛出你无法控制的异常,因此你必须中间人/过路人处理那些在到达BCL之前会触发这些异常的事情。有些情况下,你根本没有任何防御措施。例如,使用MongoClient连接到MongoDB数据库。如果在某些情况下不成功,所有的MongoCollection.*Async函数都会抛出异常,但实际上并不会抛出很多,我相信这些情况都是罕见的(这将导致情况偏向于上下文部分)。不过我也可能错了。我只是认为它们只在罕见的情况下抛出异常。正如你所指出的,你知道它们很慢,所以只有在需要事情不慢的情况下才使用它们。简单明了。

0

关于捕获异常所涉及到的性能,这里有一点需要注意。

当执行路径进入`try`块时,没有任何神奇的事情发生。没有`try`指令,也没有与进入或退出try块相关的成本。有关尝试块的信息存储在方法的元数据中,并且每当引发异常时都会在运行时使用此元数据。执行引擎沿着堆栈向下走,寻找包含在try块中的第一个调用。与异常处理相关的任何开销仅在抛出异常时发生。


1
然而,异常的存在可以影响优化——具有显式异常处理程序的方法更难进行内联,并且指令重排受到它们的限制。 - Eamon Nerbonne

-1

当编写供他人使用的类/函数时,似乎很难确定何时适用异常。BCL 的一些有用部分我不得不放弃并选择 pinvoke,因为它们会抛出异常而不是返回错误。对于某些情况,您可以解决问题,但对于其他情况,例如 System.Management 和 Performance Counters,存在需要在其中执行循环的用法,BCL 经常会抛出异常。

如果您正在编写库,并且有可能您的函数可能在循环中使用,并且存在大量迭代的潜力,请使用 Try.. 模式或其他方式来除了异常之外暴露错误。即使如此,在共享环境中由许多进程使用时,很难说您的函数将被调用多少次。

在我的代码中,只有在事情非常特殊以至于必须查看堆栈跟踪并查看出错原因并进行修复时才会引发异常。因此,我基本上已经重新编写了 BCL 的某些部分,以使用基于 Try.. 模式的错误处理而不是异常。


2
这似乎不符合张贴者“我不想讨论何时以及何时不抛出异常”的声明。 - hrbrmstr

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接