考虑以下代码:
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");
上面的代码动态调用string的Trim
方法一百万次,没有明显的开销。现在,如果我们运行以下代码:
for (int i = 0; i < 1000000; i++)
"test".Trim();
它比第一个快。第一个必须更快,因为代价高昂的动态绑定只发生一次。
我的问题是:为什么第二个比第一个跑得快?
让我们看一下ILCode
第一个使用委托,显示了很多指令,使你的修剪,循环在我看来是可怕的…
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
做简单任务的大量指令是第一个较慢的原因。例如,在循环中有四个函数调用,使得它比第二个只有一个调用的函数要慢。不同基准测试的原因很可能是您的测试环境中同时有其他进程在运行。