inline
添加关键字后,我可以通过 3 倍的性能提升来重现我的机器上的行为。
在ILSpy下并排反编译两个版本会得到几乎相同的 C# 代码。显着的区别在于两个相等测试:
// Version without inline
bool IEqualityComparer<Program.Pair<a>>.System-Collections-Generic-IEqualityComparer(Program.Pair<a> x, Program.Pair<a> y)
{
a v@ = x.v@;
a v@2 = y.v@;
if (LanguagePrimitives.HashCompare.GenericEqualityIntrinsic<a>(v@, v@2))
{
a w@ = x.w@;
a w@2 = y.w@;
return LanguagePrimitives.HashCompare.GenericEqualityIntrinsic<a>(w@, w@2);
}
return false;
}
// Version with inline
bool IEqualityComparer<Program.Pair<int>>.System-Collections-Generic-IEqualityComparer(Program.Pair<int> x, Program.Pair<int> y)
{
int v@ = x.v@;
int v@2 = y.v@;
if (v@ == v@2)
{
int w@ = x.w@;
int w@2 = y.w@;
return w@ == w@2;
}
return false;
}
泛型相等的效率远低于专门的版本。
我还注意到 Gen 0 GC 的数量与内联代码和非内联代码的巨大差异。
有人可以解释为什么会有如此巨大的差异吗?
看一下F# 源代码GenericEqualityIntrinsic
中的函数:
let rec GenericEqualityIntrinsic (x : 'T) (y : 'T) : bool =
fsEqualityComparer.Equals((box x), (box y))
它对参数进行装箱,这解释了您的第一个示例中的大量垃圾。当 GC 过于频繁地发挥作用时,它会显着减慢计算速度。第二个示例(使用)在structinline
时几乎不会产生垃圾。Pair
也就是说,inline
在调用站点使用专用版本时,这是关键字的预期行为。我的建议是始终尝试在相同的基准上优化和衡量您的代码。
您可能对一个非常相似的线程感兴趣为什么这个 F# 代码这么慢?.