Performance 设计-遇到异常还是避免它?

Performance 设计-遇到异常还是避免它?,performance,exception,Performance,Exception,我有一个简短的设计问题要问大家。我有一个方法,它必须尽可能快地执行,但它也必须提供异常所发生错误的信息 在一个循环中,函数可能会被调用一千次,但异常很少发生(如果我正确理解了您的问题,您会问:我应该(1)允许异常发生,还是(2)我应该主动测试输入变量(思考:防御驱动) 我的想法 如果可能,您应该尽快检测错误数据 尽可能。调用链中的第一个方法应该处理 这个问题 如果FastMethod方法是朝外的(例如,公共API上的方法),那么我肯定会测试输入参数(例如,number) [项目符号不相关] 不要

我有一个简短的设计问题要问大家。我有一个方法,它必须尽可能快地执行,但它也必须提供异常所发生错误的信息


在一个循环中,函数可能会被调用一千次,但异常很少发生(如果我正确理解了您的问题,您会问:我应该(1)允许异常发生,还是(2)我应该主动测试输入变量(思考:防御驱动)

我的想法

  • 如果可能,您应该尽快检测错误数据 尽可能。调用链中的第一个方法应该处理 这个问题
  • 如果FastMethod方法是朝外的(例如,公共API上的方法),那么我肯定会测试输入参数(例如,number)
  • [项目符号不相关]
  • 不要过早地陷入优化的陷阱。性能真的是个问题吗
  • 正如michaelb958所指出的,您的第二个示例没有起到任何作用。更糟糕的是,您只需捕获并重新抛出异常,就不必要地增加了额外的时钟周期
  • 如果没有更多信息,我会说: -使用场景1:测试输入参数以确保其在范围内

    额外阅读

    更新1 正如MSalters在他的
    LibFoo::WiggleBar()
    注释中正确指出的那样:参数检查应该放在调用链的最低级别。一般来说,我会以这种方式实现我的代码。谢谢MSalters让我明白过来

    我最初的想法是:bullet#1:如果性能确实是一个问题,那么获得时钟周期的一种方法是避免不必要地添加到调用堆栈中

    @Tim Krüger:除非你100%确定性能会成为一个问题……我会专注于编写可维护+易于阅读+无bug的代码

    更新2
    删除了项目符号3。

    如果我正确理解了你的问题,你会问:我应该(1)允许异常发生,还是(2)我应该主动测试输入变量(思考:防御性驾驶)

    我的想法

  • 如果可能,您应该尽快检测错误数据 尽可能。调用链中的第一个方法应该处理 这个问题
  • 如果FastMethod方法是朝外的(例如,公共API上的方法),那么我肯定会测试输入参数(例如,number)
  • [项目符号不相关]
  • 不要过早地陷入优化的陷阱。性能真的是个问题吗
  • 正如michaelb958所指出的,您的第二个示例没有起到任何作用。更糟糕的是,您只需捕获并重新抛出异常,就不必要地增加了额外的时钟周期
  • 如果没有更多信息,我会说: -使用场景1:测试输入参数以确保其在范围内

    额外阅读

    更新1 正如MSalters在他的
    LibFoo::WiggleBar()
    注释中正确指出的那样:参数检查应该放在调用链的最低级别。一般来说,我会以这种方式实现我的代码。谢谢MSalters让我明白过来

    我最初的想法是:bullet#1:如果性能确实是一个问题,那么获得时钟周期的一种方法是避免不必要地添加到调用堆栈中

    @Tim Krüger:除非你100%确定性能会成为一个问题……我会专注于编写可维护+易于阅读+无bug的代码

    更新2
    删除了项目符号3。

    另一个选项是将catch块移动到调用方的一个级别之上,这样就不会在每次迭代中再次设置try/catch块。当然,只有当您不想在异常后继续循环时,它才起作用


    一般性能建议:将不完全需要的所有内容移出循环。尽早捕获错误可能会与规则冲突,但这是一个折衷办法。

    另一个选项是将捕获块移到调用方的一个级别以上,因此不会为每次迭代重新设置try/catch块。cou的作品rse仅当您不想在异常后继续循环时


    一般性能建议:将不完全需要的所有内容移出循环。可能与尽早捕获错误的规则冲突,但这是一种折衷。

    catch(Exception ex){throw ex;}
    是完全无用的代码。无论如何,运行时都是这样做的。如果
    catch
    块除了重试之外什么都不做,它就不应该在那里。因此,您会建议首先进行参数验证吗?我不确定涉及多少个参数验证。为了保持验证的准确性,您可以将验证分组适当地使用
    |
    s和
    &&
    s。另一种方法是传递一个事先经过充分验证的数字,以避免使用FastMethod验证它。@TimKrüger我不推荐任何东西;我只是指出一些死ASCII权重。@michaelb958它比无用更糟糕,会丢失原始堆栈跟踪。
    catch(异常示例){throw ex;}
    是完全无用的代码。无论如何,运行时都是这样做的。如果
    catch
    块除了重试之外什么都不做,它就不应该在那里。因此,您会建议首先进行参数验证吗?我不确定涉及多少个参数验证。为了保持验证的准确性,您可以将验证分组适当地使用
    |
    s和
    &
    s。另一种方法是传递一个事先经过充分验证的数字,以避免快速方法验证。@TimKrüger我不推荐任何东西,我只是指出
    int FastMethod(int number)
    {
        if (number <= 0)
        {
            throw new ArgumentOutOfRangeException();
        }
        // (...) more parameter validations
    
        // do some operations with the number here
    }
    
    int FastMethod(int number)
    {
        try
        {
            // do some operations with the number here
        }
        catch (Exception ex)
        {
            throw (ex);
        }
    }