在这个问题Why is this F# code so slow?中,讨论了结构比较使函数let min3(a, b, c) = min a (min b c)
变慢;简单类型的结构比较不应该像原生类型一样快吗?
我感到很困惑,因为人们在FSharp runs my algorithm slower than Python中总是在F#中使用HashIdentity.Structural
字典。如果我有一个简单类型(int或string)作为键的字典,使用HashIdentity.Structural
会对性能造成影响吗?
答案 0 :(得分:3)
一般来说,我不担心比较的性能,因为典型的代码比较不太可能成为性能瓶颈。如果您确定自己遇到了性能问题并且分析显示比较是原因,那么您可以考虑如何最好地解决它。
如果确实需要考虑比较的性能,那么您可能需要了解编译器的工作原理。在您引用的第一个示例中,min3
函数的类型为'a * 'a * 'a -> 'a when 'a : comparison
。这个函数将编译成一个.NET方法,它带有3个泛型类型的参数,在C#中看起来像这样:
using LP = Microsoft.FSharp.Core.LanguagePrimitives;
T min3<T>(T a, T b, T c) {
T d = LP.HashCompare.GenericLessThanIntrinsic(b,c) ? b : c;
return LP.HashCompare.GenericLessThanIntrinsic(d,a) ? d : a;
}
GenericLessThanIntrinsic
方法也是通用的,并且在其中必须有基于所比较的实际类型执行比较的逻辑。这可能需要一些类型测试和虚拟方法调用。这些并不是非常昂贵的操作,但它们比直接比较两个整数值要慢得多。因此,如果比较构成了工作负载的很大一部分,那么使用通用比较例程可能会对整体性能产生很大影响,并且专门研究min3
函数只能对整数而不是任何通用值进行处理。一场巨大的表现胜利。
同样,如果您只是将整数存储为字典键,那么在键上使用内置的GetHashCode()
和Equals()
实现(这是字典默认执行的操作)将比使用结构比较。但是,这对你来说是否是一个重要的区别将取决于你正在编写的实际代码 - 正如我之前所说的,关键比较占据算法运行时间的很大一部分是不常见的。 / p>