Как упоминалось в комментариях, разница основана не на различии между C# и F #, а на различии между неизменяемой древовидной картой и изменяемым словарем на основе хеш-таблицы.
Использование #time
, я получаю следующую производительность в F # interactive:
#time
// Immutable tree-based F# map (~14 sec)
let mutable map = Map.empty
for i in 0 .. 10000000 do
map <- Map.add i i map
// Mutable hashtable-based .NET dictionary (~0.3 sec)
let dict = System.Collections.Generic.Dictionary<_, _>()
for i in 0 .. 10000000 do
dict.Add(i, i)
Интересный вопрос - можно ли сделать неизменяемую карту F # быстрее? В принципе, вы можете построить карту быстрее, если знаете, что работаете с уже отсортированным массивом. Карта F # не имеет операции, которая позволила бы вам это сделать, но ее можно было бы добавить.
Когда я определяю свой собственный тип карты, который разделяет межсетевую структуру с картой F #:
type MapTree<'Key, 'Value when 'Key : comparison > =
| MapEmpty
| MapOne of 'Key * 'Value
| MapNode of 'Key * 'Value * MapTree<'Key, 'Value> * MapTree<'Key, 'Value> * int
Затем я могу определить операцию ofSortedArray
:
let height = function
| MapEmpty -> 0
| MapOne _ -> 1
| MapNode(_, _, _, _, h) -> h
let rec ofSortedArray (data:_[]) i j =
if i = j then MapOne(data.[i])
elif i > j then MapEmpty
else
let m = i + (j - i) / 2
let l, r = ofSortedArray data i (m - 1), ofSortedArray data (m + 1) j
let k, v = data.[m]
MapNode(k, v, l, r, 1 + (max (height l) (height r)))
Это все еще далеко не так эффективно, как изменяемая хеш-таблица, но я получаю следующее:
// Immutable tree-based F# map, using sorted array
let arr = [| for i in 0 .. 10000000 -> i, i |] // ~1 sec
let map = ofSortedArray arr 0 10000000 // ~3 sec
Если вы на самом деле хотел использовать это, вам понадобится ваша собственная версия карты F # - или вы могли бы отправить запрос на перенос в основные библиотеки F #, добавив поддержку чего-то вроде этого!