C# C语言中嵌套函数的性能#

C# C语言中嵌套函数的性能#,c#,performance,function,nested,C#,Performance,Function,Nested,以下哪一个代码段会导致最少的开销(或者IL是相同的)?我的程序可能会生成巨大的锯齿状数组,这取决于我提供给它的约束公式的数量。我想限制十进制[]对象不必要的内存分配: decimal[][] originalFormTableau = CreateOriginalFormTableau(); decimal[][] standardFormTableau = InsertSlackVariables(originalFormTableau); this.Engine = new SimplexE

以下哪一个代码段会导致最少的开销(或者IL是相同的)?我的程序可能会生成巨大的锯齿状数组,这取决于我提供给它的约束公式的数量。我想限制十进制[]对象不必要的内存分配:

decimal[][] originalFormTableau = CreateOriginalFormTableau();
decimal[][] standardFormTableau = InsertSlackVariables(originalFormTableau);
this.Engine = new SimplexEngine(standardFormTableau, normalizationThreshold);

或任何其他建议(可能改用ref?

将其分解:

//we start with a space on the stack from a local or parameter
//holding whatever normalizationThreshold is
//1. Create a space on the stack to hold a decimal[][]
//Call CreateOriginalFormTableau() method
//assign result to that space.
decimal[][] originalFormTableau = CreateOriginalFormTableau();
//2. Create a space on the stack to hold a decimal[][]
//Call InsertSlackVariables() method, passing in the first decimal[][]
//assign result to that second space.
decimal[][] standardFormTableau = InsertSlackVariables(originalFormTableau);
//3. Call the Engine setter with the second space or assign it to the Engine field.
this.Engine = new SimplexEngine(standardFormTableau, normalizationThreshold)
VS:

它们是完全相同的代码,但一个版本给出了另一个版本未命名的代码的名称


在调试版本中,它们的性能可能略有不同,尽管我对此表示怀疑(有些时候,发布版本重用堆栈插槽,而调试版本不重用堆栈插槽,因此即使在不再使用它们之后,您也可以检查范围内变量,但最有可能的是,它也不会重用未命名的插槽,即使它确实产生了影响,影响也很小)。

进行了测试,用于科学:

第1版

public void Test1()
{
    decimal[][] originalFormTableau = CreateOriginalFormTableau();
    decimal[][] standardFormTableau = InsertSlackVariables(originalFormTableau);
    this.Engine = new SimplexEngine(standardFormTableau, normalizationThreshold);
}
产出:

.method public hidebysig instance void Test1() cil managed
{
    .maxstack 4
    .locals init (
        [0] valuetype [mscorlib]System.Decimal[][] originalFormTableau,
        [1] valuetype [mscorlib]System.Decimal[][] standardFormTableau)
    L_0000: ldarg.0 
    L_0001: call instance valuetype [mscorlib]System.Decimal[][] ConsoleApplication2.Class2::CreateOriginalFormTableau()
    L_0006: stloc.0 
    L_0007: ldarg.0 
    L_0008: ldloc.0 
    L_0009: call instance valuetype [mscorlib]System.Decimal[][] ConsoleApplication2.Class2::InsertSlackVariables(valuetype [mscorlib]System.Decimal[][])
    L_000e: stloc.1 
    L_000f: ldarg.0 
    L_0010: ldloc.1 
    L_0011: ldarg.0 
    L_0012: call instance object ConsoleApplication2.Class2::get_normalizationThreshold()
    L_0017: newobj instance void ConsoleApplication2.SimplexEngine::.ctor(valuetype [mscorlib]System.Decimal[][], object)
    L_001c: call instance void ConsoleApplication2.Class2::set_Engine(class ConsoleApplication2.SimplexEngine)
    L_0021: ret 
}
.method public hidebysig instance void Test2() cil managed
{
    .maxstack 8
    L_0000: ldarg.0 
    L_0001: ldarg.0 
    L_0002: ldarg.0 
    L_0003: call instance valuetype [mscorlib]System.Decimal[][] ConsoleApplication2.Class2::CreateOriginalFormTableau()
    L_0008: call instance valuetype [mscorlib]System.Decimal[][] ConsoleApplication2.Class2::InsertSlackVariables(valuetype [mscorlib]System.Decimal[][])
    L_000d: ldarg.0 
    L_000e: call instance object ConsoleApplication2.Class2::get_normalizationThreshold()
    L_0013: newobj instance void ConsoleApplication2.SimplexEngine::.ctor(valuetype [mscorlib]System.Decimal[][], object)
    L_0018: call instance void ConsoleApplication2.Class2::set_Engine(class ConsoleApplication2.SimplexEngine)
    L_001d: ret 
}
第2版

this.Engine = new SimplexEngine(
    InsertSlackVariables(
    CreateOriginalFormTableau()),
    normalizationThreshold);
产出:

.method public hidebysig instance void Test1() cil managed
{
    .maxstack 4
    .locals init (
        [0] valuetype [mscorlib]System.Decimal[][] originalFormTableau,
        [1] valuetype [mscorlib]System.Decimal[][] standardFormTableau)
    L_0000: ldarg.0 
    L_0001: call instance valuetype [mscorlib]System.Decimal[][] ConsoleApplication2.Class2::CreateOriginalFormTableau()
    L_0006: stloc.0 
    L_0007: ldarg.0 
    L_0008: ldloc.0 
    L_0009: call instance valuetype [mscorlib]System.Decimal[][] ConsoleApplication2.Class2::InsertSlackVariables(valuetype [mscorlib]System.Decimal[][])
    L_000e: stloc.1 
    L_000f: ldarg.0 
    L_0010: ldloc.1 
    L_0011: ldarg.0 
    L_0012: call instance object ConsoleApplication2.Class2::get_normalizationThreshold()
    L_0017: newobj instance void ConsoleApplication2.SimplexEngine::.ctor(valuetype [mscorlib]System.Decimal[][], object)
    L_001c: call instance void ConsoleApplication2.Class2::set_Engine(class ConsoleApplication2.SimplexEngine)
    L_0021: ret 
}
.method public hidebysig instance void Test2() cil managed
{
    .maxstack 8
    L_0000: ldarg.0 
    L_0001: ldarg.0 
    L_0002: ldarg.0 
    L_0003: call instance valuetype [mscorlib]System.Decimal[][] ConsoleApplication2.Class2::CreateOriginalFormTableau()
    L_0008: call instance valuetype [mscorlib]System.Decimal[][] ConsoleApplication2.Class2::InsertSlackVariables(valuetype [mscorlib]System.Decimal[][])
    L_000d: ldarg.0 
    L_000e: call instance object ConsoleApplication2.Class2::get_normalizationThreshold()
    L_0013: newobj instance void ConsoleApplication2.SimplexEngine::.ctor(valuetype [mscorlib]System.Decimal[][], object)
    L_0018: call instance void ConsoleApplication2.Class2::set_Engine(class ConsoleApplication2.SimplexEngine)
    L_001d: ret 
}
在发行版中编译,优化打开了。我不得不说,由于局部变量没有在方法中重用,我相信编译器会将
Test1
重写为
Test2
。不知何故,它没有。所以我猜
Test2
会稍微快一点,尽管它可能无法测量


因此,除非您正在搜索微秒级优化,否则请选择可读性最好的。

如果您真的要考虑这些微秒级优化,您就有麻烦了。为什么?我知道早期优化是有害的,我没有遇到任何明显的性能问题,但我更喜欢以正确的方式进行操作。您真的能够回答我们吗r我的问题,先生?早期优化不是坏事,只是过早——也就是说,太早了。当然,知道这样的问题的答案是帮助我们判断某件事是否值得做的事情之一——永远,永远,或者在分析表明需要时。(而且,Knuth只是说,当他解释如何优化给定代码时,他可以避开优化的抱怨。)。谢谢Jon!关于调试与重建的有趣信息。@Heliac这种行为的实际区别在于,在调试版本中,当本地引用在作用域中时,大多数对象都无法收集。在发布版本中,它们可以在上次使用本地时立即收集。当
Timer
s在s中被收集时,会引发一些意外cope.+1但请注意,jitted代码可能比这些几乎相同的IL更相似。有趣的是,我刚刚注意到,虽然它们非常接近,但jitted可能更相似,正如我所说,尽管第二种情况刚好在适合内联的大小之下,而第一种情况只是太大了一个字节。现在,这些规则还没有标准化,甚至可能已经被修改,但尽管我坚持认为这通常不会产生真正的区别,但在这里,通常可以忽略的区别只会触及阈值的任何一边,这可能会导致一些问题。