尝试..手表块总是很贵?

时间:2010-01-15 22:21:24

标签: c# performance exception try-catch

  

可能重复:
  Do try/catch blocks hurt performance when exceptions are not thrown?

嘿大家,  关于try..catch块的快速问题。我听说它们使用起来很昂贵,不应该用作程序流程的一部分。但是,为了验证电子邮件地址,我使用以下代码。

        try
        {
            MailAddress checkEmail = new MailAddress(testEmail);

            return true;
        }
        catch
        {
            return false;
        }

由于事先验证,除非是试图绕过验证,否则我没有多少例外被捕获。我的问题是,尝试...如果捕获到异常,Catch块只会很昂贵,或者无论是否抛出任何异常,总是昂贵?

谢谢

编辑:感谢所有回复。我已经决定,因为检查(在C#中)不是很昂贵,我会坚持使用这种方法。这主要是因为抛出的实际异常很少,因为先前的验证步骤确保没有人意外输入无效的电子邮件地址。

10 个答案:

答案 0 :(得分:20)

general 中,在今天的实现中,输入try块并不昂贵(这并非总是如此)。但是,抛出和处理异常通常是一项相对昂贵的操作。因此,异常通常应用于异常事件,而不是正常的流量控制。

性能只是需要考虑的一个因素,尤其是在现代世界。如果(例如)你正在做一次响应用户操作的事情,那么从性能角度来看,即使你可以进行主动检查,你是否使用异常并不重要,只要异常发生得足够快用户不是jolted.¹但是如果你在一个紧凑的循环中做一些事情会运行数十万次,或者你正在编写一个可能需要处理巨大负载的web应用程序,你可能我希望避免在正常情况下使用例外。


¹十多年前,我负责增强.Net 1.1“无触摸部署”应用程序,其中第一次抛出异常需要三秒钟。在一个用例中涉及打开文件时,这是一个足够的问题,用户要求的文件可能合理地不存在,我必须在尝试打开文件之前添加对文件存在的检查,这通常是糟糕的编程习惯(只是尝试打开文件并处理异常(如果失败),纯粹是因为等待该异常构建的用户体验非常糟糕。但那可能不是我们现在生活的世界。

答案 1 :(得分:2)

除非有例外情况,否则它们相当便宜。因此,当您需要例外时,应该避免使用它们,如上例所示。

我认为不良用户输入的例外通常是不明智的。内存不足或其他意外故障的例外情况很好。

答案 2 :(得分:2)

只是为了扮演恶魔倡导者 - 我发现使用Exceptions进行流量控制非常有用:“取消”按钮。

如果你的某个服务上运行的函数可能需要10-120分钟,这会做很多不同的事情,我发现if(hasCanceled)在我的Log()中抛出新的JobCancelledException()功能(记录我正在的每一步)只是为了工作而感到非常棒。它摆脱了当前代码的执行并停止运行作业 - 正是我需要的。我确信有一些更好的方法可以做到这一点,也许以某种方式使用事件 - 但对于我的情况,它工作得很好(特别是因为工作没有定期取消)。

除此之外 - 我100%同意Exceptions永远不应该用作流量控制工具..

@Kornel - 我对这篇文章有两个字......神圣的$ hit =)

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

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
             }
}

答案 3 :(得分:1)

如果抛出异常,异常只会很昂贵。我确信设置一个Try..Catch块有一些非常小的成本,但它远远超过了根本没有捕获异常并导致程序崩溃的成本。正如其他人所指出的那样,Try..Catch块只应用于特殊情况。

答案 4 :(得分:1)

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

答案 5 :(得分:1)

如果抛出异常,它的成本很高,但这不是将异常用作正常流控制的借口。

如果您可以预先验证某些内容以避免首先发生异常,那么请执行此操作。例如。而不是你发布的内容,这样的事情会更好:

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

规则的例外情况是,您必须滚动自己版本的复杂方法(例如,在基类库中找到的没有TryParse方法的东西),以避免异常在宏观方案中,无所谓

如果您不确定,请使用代表性数据进行配置。如果用户每隔一秒在客户端应用程序表单中输入数据,则无关紧要。但是,如果它是用于处理可能来自任何地方的数千个电子邮件地址的服务,那么您应该确定您的假设。

答案 6 :(得分:0)

绝不应将

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

如果您不相信,请阅读this thread

答案 7 :(得分:0)

通常,现代编译器仅对try块施加最小成本,除非抛出异常。它们仍然不应该用于程序流控制,因为它们不像标准流程结构那样明显。异常基本上等同于COME FROM语句。

答案 8 :(得分:0)

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

答案 9 :(得分:0)

这是依赖于语言的,但据我所知,如果没有抛出异常,那么try / catch就没有性能成本。

因此,在您使用预先验证的电子邮件地址的示例中,您所拥有的内容很好。