Вообще говоря, я не буду беспокоиться о производительности сравнений, потому что для типичного сравнения кода очень маловероятно, что это будет узким местом в производительности. Если вы определили, что у вас есть проблема с производительностью, и профилирование показывает, что причиной являются сравнения, то вы можете подумать, как лучше всего ее устранить.
Если вам нужно учитывать производительность сравнений, то вам, возможно, нужно понять, как работает компилятор. В первом примере, который вы цитировали, функция 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()
для ключей (что по умолчанию будет делать словарь) будет быстрее, чем структурное сравнение. Однако, будет ли это важным для вас отличием, будет зависеть от того, какой код вы пишете - как я уже говорил ранее, для ключевых сравнений довольно необычно занимать значительную долю времени работы алгоритма.