TL; DR :我可以以某种方式创建一个可以在内循环中使用不同功能的算法,并且仍然可以获得"功能"内联,无需借助复制/粘贴或if / else语句?
我正在尝试创建一个基本上如下的算法:
for(var i=0; i<big; i++) {
for(var j=0; j<big2; j++) {
// ... processing
var x = SomeFunc(a, b, c);
// ... more processing
}
}
我希望算法能够运行许多可能的函数(上面SomeFunc
),每次运行都会调用很多次函数。每个SomeFunc
函数都非常简单(通常是算术表达式)。
现在,为了从该算法中获得可接受的性能,必须内联SomeFunc
。但是我仍然没有内联函数,同时仍然允许多个函数。
我意识到这意味着算法函数必须被多次JIT,但我希望像这样的构造能够工作:
interface ISomeFunc {
int SomeFunc(int a, int b, int c);
}
private sealed class SomeFunc1 : ISomeFunc {
public int SomeFunc(int a, int b, int c) {
return ....;
}
}
private static void RunMyGenericAlgo<T>(T func) where T : ISomeFunc
{
for ... for ..
x = func.SomeFunc(a, b, c);
}
但似乎函数调用没有内联,因为上面的func
是通过接口而不是通过密封类调用的。
我也尝试过这种明显的方法:
abstract class MyAlgo {
protected abstract int SomeFunc(int a, int b, int c);
public void Run() {
// as RunMyGenericAlgo above
}
}
sealed class MyAlgoSomeFunc1 : MyAlgo {
protected override int SomeFunc(int a, int b, int c) {...}
}
它也没有内联。
然而,该程序将根据需要内联(并且运行速度提高约50%):
class MyAlgo {
int SomeFunc(int a, int b, int c) {...}
public void Run() {
// as above
}
}
编辑:要澄清,我还调查了使用MethodImpl
AggressiveInlining
属性进行调查,但似乎没有帮助。
我在C#中尝试甚至是可能的,还是我必须为我的内部函数的每个实现复制/粘贴算法?
答案 0 :(得分:2)
要允许内联方法,实现必须是常量(例如,不依赖于变量)。因此,任何形式的虚拟/抽象/接口/委托调用都是一个永远不能内联的调用。 因此,唯一的方法是进行非虚方法调用,或者只是将代码粘贴到那里。
此规则有一些例外情况。例如,JVM设计人员存在默认情况下所有Java方法都是虚拟的问题,它们具有虚拟调用内联。这将做类似的事情:
//calling obj.MyVirtCall();
if (obj.Type == MyCommonType) {
//inlined code for MyCommonType.MyVirtCall();
} else {
obj.MyVirtCall();
}
修改强>
您可以使用T4 templates为算法示例中的每个Run
覆盖生成C#代码,不需要重复代码,但是它可能会使维护稍微复杂一些,还必须维护T4模板而不是只是C#代码。