这是我想要做的其他事情的过度简化的例子,但是,现在,请考虑这些投射方法:
public static string StringTryCast(object o)
{
return o as string;
}
public static T RefTypeTryCast<T>(object o) where T : class
{
return o as T;
}
当我在50,000,000次迭代的循环中执行它们时,我似乎比执行强制转换的内容要慢得多。以下是我正在进行的四项测试,其评论与他们下面的测试案例相对应。
object BoxedValue = "my string";
//inline trycast
() => { s = BoxedValue as string; }
//method: RefTypeTryCast
() => { s = RefTypeTryCast<string>(BoxedValue); }
//method: StringTryCast
() => { s = StringTryCast(BoxedValue); }
以下是测试结果。我为每种方法运行了五次50,000,000次迭代测试,然后计算了平均值。
inline trycast 50,000,000x...
368 ms
370 ms
374 ms
380 ms
380 ms
374.4 ms average over 5 iterations
method: RefTypeTryCast 50,000,000x...
1083 ms
1098 ms
1100 ms
1133 ms
1138 ms
1110.4 ms average over 5 iterations
method: StringTryCast 50,000,000x...
477 ms
478 ms
487 ms
489 ms
493 ms
484.8 ms average over 5 iterations
At 50,000,000 iterations, inline trycast is...
1.2949 x Faster than method: StringTryCast
2.9658 x Faster than method: RefTypeTryCast
我无法理解为什么StringTryCast
在辅助方法中进行内联强制转换时会有不同的表现。在方法中添加[MethodImpl(MethodImplOptions.AggressiveInlining)]
似乎没有帮助。此外,RefTypeTryCast
使用泛型并执行比内联更差3倍。
好像他们都应该表现得相对一样。
编辑:正如评论中所提到的,我使用帮助程序类来运行我的测试。这基本上就是封装逻辑。
Stopwatch sw = new Stopwatch();
for (i = 0; i < 5; i++)
{
sw.Restart();
for (int o = 0; o < 50000000; o++)
{
Test(); //anon method passed in from lambda expression
}
sw.Stop();
times.Add(i, sw.ElapsedMilliseconds);
}
答案 0 :(得分:3)
这是发布版本。
dat<-filter(dat,-node_id==9)
dat<-subset(dat,-node_id==9)
如您所见,在泛型函数的情况下还有一条指令:IL code for `StringTryCast` and `RefTypeTryCast`:
.method public hidebysig static !!T RefTypeTryCast<class T> (object o) cil managed
{
IL_0000: ldarg.0
IL_0001: isinst !!T
IL_0006: unbox.any !!T
IL_000b: ret
}
.method public hidebysig static string StringTryCast (object o) cil managed
{
IL_0000: ldarg.0
IL_0001: isinst [mscorlib]System.String
IL_0006: ret
}
。从https://msdn.microsoft.com/en-us/library/system.reflection.emit.opcodes.unbox_any.aspx我们可以看到它执行了三个操作:将对象推送到堆栈,从堆栈弹出和取消装箱,然后推回堆栈。所以,还有更多的工作要做,因此有更多的时间。
对于内联和unbox.any
之间的区别,如果是内联,你有一个推送到堆栈,检查堆栈上的内容是否为字符串,然后从堆栈中弹出。
对于StringTryCast
,有推送到堆栈,调用方法将参数推送到堆栈,检查它是否是字符串,返回它将其从堆栈推送到调用者的堆栈然后当它#39 ; s,它再次从堆栈中弹出。
再一次,更多的工作 - &gt;更多时间。