关于c#:Try..Catch块总是很贵?

Try..Catch blocks always expensive?

本问题已经有最佳答案,请猛点这里访问。

Possible Duplicate:
Do try/catch blocks hurt performance when exceptions are not thrown?

嘿,大家好,只是一个关于尝试的快速问题。抓住障碍物。我听说它们的使用成本很高,不应该作为程序流的一部分使用。但是,为了验证电子邮件地址,我使用了以下代码。

1
2
3
4
5
6
7
8
9
10
        try
        {
            MailAddress checkEmail = new MailAddress(testEmail);

            return true;
        }
        catch
        {
            return false;
        }

由于之前的验证,我没有太多要捕获的异常,除非它试图绕过验证。我的问题是,Try…Catch块只有在捕获异常时才昂贵,还是无论是否引发异常,它总是很昂贵?

谢谢

编辑:谢谢所有的回复。我已经决定,由于检查(在C)不是很贵,我将坚持这个方法。这主要是因为很少会引发实际的异常,因为之前有一些验证步骤可以确保没有人意外地输入无效的电子邮件地址。


一般来说,在今天的实现中,输入try块一点都不昂贵(这并不总是正确的)。然而,抛出和处理异常通常是一个相对昂贵的操作。因此,异常通常应用于异常事件,而不是正常的流控制。

不过,性能只是需要考虑的一个因素,尤其是在现代世界。如果(例如)您在响应用户操作时执行过某项操作,那么从性能角度来看,是否使用异常(即使您可以进行主动检查),也可能无关紧要,前提是异常发生得足够快,用户不会受到震动。1但如果您执行的操作是紧密循环的,而不是o运行数十万次,或者您正在编写可能需要处理大量负载的Web应用程序,您可能希望避免在正常情况下使用异常。

1十多年前,我负责增强.NET 1.1"无接触部署"应用程序,在该应用程序中引发的第一个异常花费了整整三秒钟。在一个涉及打开用户要求的文件的用例中,这是一个足够的问题,在试图打开该文件之前,我必须添加一个文件存在性检查,这通常是糟糕的编程实践(如果失败,只需尝试打开该文件并处理异常),纯粹是因为用户将里恩斯等着那次例外的建设实在是太差了。但那可能不是我们现在生活的世界。


只是为了扮演恶魔拥护者-我发现了一个很好的使用异常流控制:取消按钮。

如果您有一个函数在某些服务上运行,可能需要10-120分钟,这是在做很多不同的事情,我发现如果(已经取消)在我的log()函数(在我所处的每个步骤中都会记录)中抛出新jobCancelledException(),那么它的工作就非常棒。它摆脱了当前代码的执行,停止了运行作业——这正是我需要的。我确信有更好的方法可以做到这一点,也许可以通过某种方式利用事件——但对于我来说,这很有效(尤其是因为工作没有被定期取消)。

另外,尽管如此,我完全同意例外永远不应该被用作流控制工具。

@科内尔-我有两个字写那篇文章…神圣$IT =

下面是一个简单的伪代码示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
Class Job
{
       Public Run(param1,param2,etc...)
       {
             Try
            {
                   Log("Doing Something")
                   DoSomething()

                         Log("Doing Another")
                         DoAnother()

                         Log("This keeps going, etc, inside of these function we make the same Log calls where it makes sense")
                         Etc()
                   }
                   Catch(JobCancelledException)
                   {
                        status="Cancelled"
                   }
            }

              Private Log(ByVal str As String)
              {
                      MessateToUser(str)

                      if(hasCancelled)
                          throw new JobCancelledException
            }

             private SomeEvent_WhenUserPushesCancelButton()
             {
                       hasCancelled=True
             }
}


它们很便宜,除非有例外。因此,当需要异常时,您应该避免使用它们,如上面的示例所示。

我认为错误的用户输入的异常通常是不明智的。内存不足或其他意外故障的异常是正常的。


只有当抛出异常时,它才是昂贵的,但这并不是使用异常作为正常流控制的借口。

如果您可以预先验证某些内容,以避免在第一时间发生异常,那么就这样做。例如,与您发布的内容不同,这样的内容更可取:

1
2
string invalidAddress ="notvalid@@@@@@lolzors.bomb";
return MailAddressValidator.IsValid(invalidAddress ); // doesn't cause exception

这条规则的例外是,当您需要滚动自己版本的复杂方法(例如,在基类库中发现的某个没有TryParse方法的方法)时,为了避免一个例外,在总体方案中,这并不重要。

如果您不确定,请使用代表性数据进行分析。如果是用户每隔一秒钟在客户端应用程序表单中输入数据,那就没关系了。然而,如果这是一个处理成批成千上万的电子邮件地址的服务,可能来自任何地方,你应该确定你的假设。


try块的开销非常低,因此如果没有抛出异常,那么就没有明显的惩罚。当抛出异常时发生的主要开销是在寻找处理程序时进行的堆栈遍历-由于您将异常缓存到离源如此近的位置,所以我怀疑会有很多性能问题。理想情况下,虽然您可以预先正确地验证您的输入,但电子邮件验证相当复杂,因此在这种情况下,它可能不值得。


只有在抛出异常时,异常才是昂贵的。我敢肯定设置一个try..catch块的成本是非常低的,但是它远远超过了不捕获异常和程序崩溃的成本。正如其他人所指出的那样,试一下……挡块只能在特殊情况下使用。


try..catch块不应用作程序流控制的工具。

如果你不相信的话,请阅读这篇文章。


这是语言依赖的,但据我所知,在Java中,如果没有抛出异常,EDCOX1×1 /EDCOX1(5)就不存在性能开销。

因此,在使用预先验证过的电子邮件地址的示例中,您拥有的内容是可以的。


虽然您永远不应该使用try..catch进行程序流控制,但是如果代码中没有实际抛出异常,我就不知道有任何性能问题。


一般来说,除非抛出异常,否则现代编译器只对try块施加最小的成本。它们仍然不应该用于程序流控制,因为它们不像标准流构造那样明显。异常本质上等同于COME FROM语句。