这些方法中的哪一种会产生最快的运行时间?

时间:2012-03-29 17:35:46

标签: c# performance delegates function-pointers

我正处于一个简短的思想实验中,并希望得到一些帮助。

考虑一个类,它根据一个可以改变的函数计算一些输出,但只能根据预定的集合进行更改。

或者,一些功能列表:

double function1(double input){
    //perform some operations
    return output;
}

double function2(double input){
    //perform some operations
    return output;
}

double function3(double input){
    //perform some operations
    return output;
}

double function4... etc.

现在假设这些函数包含在某个类中,该类预定了在调用类来计算某个值时使用的函数

Class Calculate{

    int whichFunction = 2;

    double calculate (double input){

    //decide which function to use
    switch(whichFunction){
        case 1:
            return function1(input);
            break;
        case 2:
            return function2(input);
            break;
        case 3:
            return function3(input);
            break;
        case 4... etc..
    }

    ... predetermined functions here....
}

当然,执行此操作的第一个想法是只需打开值并继续前进。但是,如果我们不使用开关,只需将功能更改为运行?

Class Calculate{

    Func<double> whichFunction;

    double calculate (double input){
        return whichFunction.Invoke(input);
    }

    void setFunction(int functionNumber){
        switch(whichFunction){
        case 1:
            whichFunction = function1;
        case 2:
            whichFunction = function2;
        case 3:
            whichFunction = function3;
        case 4... etc..
    }

    ... predetermined functions here....
}

考虑到您选择的哪个函数不经常更改,或者甚至可能只在构造函数中设置一次,将避免切换实际上提供运行时速度的好处,或者是以这种方式调用函数的行为否定了它的好处

其他可能的替代方案:

  1. 级联if-else ....不,可能是最慢的方法。
  2. 而不是使用Func&lt;&gt;通用,使用代理。
  3. 利用事件并简单地重新分配为事件分配的功能。
  4. 不使用Func&lt;&gt;,而是使用方法指针。
  5. 任何想法都会受到赞赏!

5 个答案:

答案 0 :(得分:3)

非常这里的决定不太可能以任何有意义的方式影响效果。我想在正常情况下执行的函数比在大多数情况下触发它的逻辑花费的时间更多。

你提到的每个代码snippits都会非常快速地运行,即使一个比另一个更快,它也不会有任何显着的余量。选择最容易理解和维护的方法,然后在发现应用程序运行速度太慢的情况下开始寻找性能增益

答案 1 :(得分:0)

如果不了解更大的图片,很难提出建议。您可能正在构建一个计算器,如果是这样,可能希望为您的函数重载实际的数学运算符。

如果您正在使用一些功能并且只能应用其中一个功能,那么可能是分层的

  • if () {} else if () {} else if () {}

......结构可能会更好地为你服务(前面更受欢迎的审讯)因为结构会在你的状况得到满足时退出执行。

当然还有&amp;&amp; amp;的短路逻辑。和||要考虑的功能。这种短路可以节省你的时间,取决于你所追求的。

答案 2 :(得分:0)

“正确”的答案是实际测量&amp;比较你的选择。 “务实”的答案是,除非你有很多功能,否则你已经花了很多时间来考虑这个问题。 “逻辑”的答案是你的第二个选项确实切换频率低得多,所以它应该更快,虽然它不是线程安全的,并且是一个尴尬的API,会导致错误的路上(调用者忘记设置功能或设置经常使它失去目的)

答案 3 :(得分:0)

<强> POITROAE。

使用分析器!

现代编译器可以使用太多优化来预测 情况下运行速度最快的内容。一般来说,

  • 函数调用是堆栈上的一系列操作并跳转到某个位置。
  • 有些编译器会针对switch语句的每种情况进行跳转
  • 有些人会跳桌,这可能是一种祝福和诅咒。
  • 如果交换机本地范围内有变量,则可以设置堆栈帧。
  • 等等...... cases几乎是无限的。

也就是说,在每种情况下只有几行代码的switch语句可能比函数调用更快。

此外,在X86上,跳转和函数调用可以清除缓存和管道,因此您也可以为此付出很高的代价。

分析器确实最适合现代软件。

答案 4 :(得分:0)

两个示例的相对性能取决于具体情况:

  1. 在大多数情况下,特别是如果多次调用calculate,switch语句中的多重比较将导致许多分支将被执行多次,并且可能被CPU错误地预测。这很容易超过Invoke版本中函数调用的成本。
  2. 如果function1..3很短并且可以内联,则可能存在编译器可以优化“切换”版本比“调用”版本略快的情况,因为没有办法优化掉后者的功能。
  3. 我的建议是使用“调用”版本,因为在大多数情况下,它会带来最佳性能。