Try-Catch vs如果在C#中的性能

时间:2016-09-26 19:33:47

标签: c# if-statement try-catch

我试图更多地了解各种设计选择的含义,并找到最有效的解决方案来防止我的代码中的错误。在深入研究之前,请允许我简要地说一下我的问题:

  

与if和if语句结构相比,try catch是否是处理越界异常的更有效的解决方案?

我理解提高异常代价很高,但是通过删除不必要的if语句可以降低成本吗?

现在,请允许我说明我的具体问题,以便为您提供更多有用的信息。

我正在制作游戏,而游戏的一部分是与探路者相结合的世界网格解决方案。游戏单元可以从世界网格请求节点(通过将坐标信息作为有序对(x,z)发送),然后发送到路径查找器或对其执行一些其他杂项操作。因为节点是以大量频率请求的,特别是通过路径查找器,这似乎是一个尝试优化的智能场所。

以下是我根据节点数组中 x z 值返回给定节点的当前代码:

public Node GetTile(int x, int z)
{
    if (x < 0)
        x = 0;
    if (x >= length_X)
        x = length_X - 1;

    if (z < 0)
        z = 0;
    if (z >= length_Z)
        z = length_Z - 1;
    return tiles [x, z];
}

正如您可以清楚地看到的那样,当从world-grid的节点数组(tile)中检索节点时,我有几个if语句以避免出现异常异常。这是最有效的解决方案吗?我可以删除if&#39;而是将返回放在try catch块中,如下所示:

public Node GetTile(int x, int z) 
{
    try
    {
        return tiles[x, z];
    }
    catch (System.IndexOutOfRangeException e)
    {
        //handle exception here
        //do smart programming fix-y stuff
    }
}

此解决方案正常运行,但有一些原因我不知道这会降低效率吗?我相信它是一个更智能的解决方案的逻辑是,我每次调用该方法时最多可以删除四次比较。考虑到程序实际发送的价值超出限制范围的情况很少见,这似乎是一个很好的权衡。但我不知道的是,异常是如何在幕后工作的。检查异常是否与手动检查值一样昂贵?

更新

在阅读完回复后,我现在对这个主题有了更好的理解。我已经对我的代码进行了一些测试,以解决运行1000万次迭代的各种情况。

根据我的一般假设,如果我们假设永远不会出现输入导致异常的情况,那么try catch块确实更快。但是,在大约10%的方法调用引发异常的情况下,性能会慢5倍以上。我测试了各种百分比,似乎在我的情况下,更好的性能阈值接近1%。

到目前为止,我还不确定有多少百分比的电话确实会引发异常,但我相信这个数字远远低于1%。因此,我可以安全地,除非进一步测试显示,否则使用try-catch块来确保我的代码运行时没有致命错误。

感谢所有贡献者。

1 个答案:

答案 0 :(得分:3)

对于不常见的事情例外,例如连接问题,xml-File不是xml格式等等。

与一些简单的if语句相比,异常的性能通常很差,但也有一些情况,异常处理可能比自己检查数据的有效性更快,特别是如果你不知道怎么做快速(例如,检查文件的xml格式是否正确)。

异常的表现取决于你在堆栈中的“深度”。因此,当您在应用程序的第24层(可能由拦截器和普通逻辑层引起)时,必须创建大量的堆栈跟踪。

您不能对异常的性能给出一般性陈述,但是当您可以避免异常时。正如他们的名字所说,它们是为例外而制作的。

您可以避免例外的一个小例子:

try
{
    LoginUser("Fooooo", "Bar");
}catch(InvalidPasswordException e){
    MessageBox.Show(e.Message);
}  

private static void LoginUser(string pUsername, string pPassword)
{
    if (pUsername != "Foo" || pPassword != "Bar")
       throw new InvalidPasswordException("Invalid username and/or password");

    GrantAccess(pUsername);
}

除了抛出异常,您还可以返回一个布尔值:

if (!LoginUser("Fooooo", "Bar"))
{
    MessageBox.Show("Invalid username and/or password");
}

private static bool LoginUser(string pUsername, string pPassword)
{
    if (pUsername != "Foo" || pPassword != "Bar")
        return false;

    GrantAccess(pUsername);            
    return true;
} 

效果测试:使用虚假凭据进行10000次尝试:

抛出异常(不显示消息框):181990454 ticks

返回布尔值:644 ticks

我们只是应用程序的一层,因此没有太多的堆栈跟踪要生成。我想你可以看到并特别感受到差异。