为什么动态绑定不快?
Why is dynamic binding not faster?
考虑以下代码:
delegate string StringToString(string s);
MethodInfo trimMethod = typeof(string).GetMethod("Trim", new Type[0]);
var trim = (StringToString)Delegate.CreateDelegate
(typeof(StringToString), trimMethod);
for (int i = 0; i < 1000000; i++)
trim("test");
上面的代码动态调用字符串的 Trim
方法一百万次而没有显着的开销。现在,如果我们 运行 以下代码:
for (int i = 0; i < 1000000; i++)
"test".Trim();
比第一个快。第一个必须更快,因为昂贵的动态绑定只发生一次。
我的问题是:为什么第二个 运行 比第一个快?
让我们看一下 ILCode
第一个使用委托,显示了很多指令来使你的 trim,循环在我看来很糟糕......
ldtoken [mscorlib]System.String
IL_0025: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
IL_002a: ldstr "Trim"
IL_002f: ldc.i4.0
IL_0030: newarr [mscorlib]System.Type
IL_0035: call instance class [mscorlib]System.Reflection.MethodInfo [mscorlib]System.Type::GetMethod(string,
class [mscorlib]System.Type[])
IL_003a: stloc.1
IL_003b: ldtoken ConsoleApplication1.Program/StringToString
IL_0040: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
IL_0045: ldloc.1
IL_0046: call class [mscorlib]System.Delegate [mscorlib]System.Delegate::CreateDelegate(class [mscorlib]System.Type,
class [mscorlib]System.Reflection.MethodInfo)
IL_004b: castclass ConsoleApplication1.Program/StringToString
IL_0050: stloc.2
IL_0051: ldc.i4.0
IL_0052: stloc.0
IL_0053: br.s IL_0065
IL_0055: ldloc.2 // start of loop
IL_0056: ldstr "test"
IL_005b: callvirt instance string ConsoleApplication1.Program/StringToString::Invoke(string)
IL_0060: pop
IL_0061: ldloc.0
IL_0062: ldc.i4.1
IL_0063: add
IL_0064: stloc.0
IL_0065: ldloc.0
IL_0066: ldc.i4 0xf4240
IL_006b: clt
IL_006d: stloc.3
IL_006e: ldloc.3
IL_006f: brtrue.s IL_0055 // iterates to next trim here
然后是另一个。
IL_0001: ldc.i4.0
IL_0002: stloc.0
IL_0003: br.s IL_0014
IL_0005: ldstr "test" // loop start
IL_000a: callvirt instance string [mscorlib]System.String::Trim()
IL_000f: pop
IL_0010: ldloc.0
IL_0011: ldc.i4.1
IL_0012: add
IL_0013: stloc.0
IL_0014: ldloc.0
IL_0015: ldc.i4 0xf4240
IL_001a: clt
IL_001c: stloc.3
IL_001d: ldloc.3
IL_001e: brtrue.s IL_0005 // iterate
执行简单任务的大量指令是第一个速度较慢的原因。例如,循环中有四次对函数的调用,这使得它比第二个只有一次调用的函数慢。基准测试不同的原因很可能是您的测试环境同时进行了其他进程。
考虑以下代码:
delegate string StringToString(string s);
MethodInfo trimMethod = typeof(string).GetMethod("Trim", new Type[0]);
var trim = (StringToString)Delegate.CreateDelegate
(typeof(StringToString), trimMethod);
for (int i = 0; i < 1000000; i++)
trim("test");
上面的代码动态调用字符串的 Trim
方法一百万次而没有显着的开销。现在,如果我们 运行 以下代码:
for (int i = 0; i < 1000000; i++)
"test".Trim();
比第一个快。第一个必须更快,因为昂贵的动态绑定只发生一次。
我的问题是:为什么第二个 运行 比第一个快?
让我们看一下 ILCode
第一个使用委托,显示了很多指令来使你的 trim,循环在我看来很糟糕......
ldtoken [mscorlib]System.String
IL_0025: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
IL_002a: ldstr "Trim"
IL_002f: ldc.i4.0
IL_0030: newarr [mscorlib]System.Type
IL_0035: call instance class [mscorlib]System.Reflection.MethodInfo [mscorlib]System.Type::GetMethod(string,
class [mscorlib]System.Type[])
IL_003a: stloc.1
IL_003b: ldtoken ConsoleApplication1.Program/StringToString
IL_0040: call class [mscorlib]System.Type [mscorlib]System.Type::GetTypeFromHandle(valuetype [mscorlib]System.RuntimeTypeHandle)
IL_0045: ldloc.1
IL_0046: call class [mscorlib]System.Delegate [mscorlib]System.Delegate::CreateDelegate(class [mscorlib]System.Type,
class [mscorlib]System.Reflection.MethodInfo)
IL_004b: castclass ConsoleApplication1.Program/StringToString
IL_0050: stloc.2
IL_0051: ldc.i4.0
IL_0052: stloc.0
IL_0053: br.s IL_0065
IL_0055: ldloc.2 // start of loop
IL_0056: ldstr "test"
IL_005b: callvirt instance string ConsoleApplication1.Program/StringToString::Invoke(string)
IL_0060: pop
IL_0061: ldloc.0
IL_0062: ldc.i4.1
IL_0063: add
IL_0064: stloc.0
IL_0065: ldloc.0
IL_0066: ldc.i4 0xf4240
IL_006b: clt
IL_006d: stloc.3
IL_006e: ldloc.3
IL_006f: brtrue.s IL_0055 // iterates to next trim here
然后是另一个。
IL_0001: ldc.i4.0
IL_0002: stloc.0
IL_0003: br.s IL_0014
IL_0005: ldstr "test" // loop start
IL_000a: callvirt instance string [mscorlib]System.String::Trim()
IL_000f: pop
IL_0010: ldloc.0
IL_0011: ldc.i4.1
IL_0012: add
IL_0013: stloc.0
IL_0014: ldloc.0
IL_0015: ldc.i4 0xf4240
IL_001a: clt
IL_001c: stloc.3
IL_001d: ldloc.3
IL_001e: brtrue.s IL_0005 // iterate
执行简单任务的大量指令是第一个速度较慢的原因。例如,循环中有四次对函数的调用,这使得它比第二个只有一次调用的函数慢。基准测试不同的原因很可能是您的测试环境同时进行了其他进程。