Javascript Immutable Map Benchmarks
Benchmarks a number of Javascript immutable map implementations:
- Javascript objects that achieve immutability though copying (using
Object.assign
). - ES6's
Map
that achieves immutability though copying. - hashtrie - 0.2.x
- HAMT - 0.1.x
- HAMT+ - 0.0.x
- mori - 0.2.x
- immutable - 2.0.x
To run the benchmarks:
$ npm install
$ npm run benchmark
The following are benchmarked:
-
Get one entry from a map of size N.
-
Put one entry into a map of size N.
-
Remove one entry from a map of size N.
-
Put N entries into a map, where each put operation is immutable.
-
Put N entries into a map, where puts may use transient mutation .
-
Remove N entries from a map, where each remove operation is immutable.
-
Remove N entries from a map, where removes may use transient mutation.
-
Get the number of entries in map of size N.
-
Get an array of keys keys for a map of size N.
-
Sum all values in map of size N.
- results
- Overview of basic Javascript hashtries and optimizations
- Overview of Javascript HAMT implementation and optimization used by the HAMT library
- HAMT, HAMT+, and Immutable are the three fasted implementations.
- These three library also perform well as the map size gets very large. It only costs ~6x as much to put an element into a HAMT map with 100000 entries as it does to put one into a HAMT map with 10 entries.
- The immutability through copying used for Object and Map is too slow to use for larger objects. Their memory usage is likely much higher as well.
- Hashtrie's sparse array storage is a major performance hit
for folds as neither
reduce
orsplice
show good performance for sparse arrays. - Both Mori and Immutable are more complete data structure libraries. This should be considered when selecting an immutable map implementation.
- Hamt's use of iterators for some operations results in some overhead in these artificial benchmarks. You can see this in the
keys
test where thefold
based implementation ofkeys
is faster thenArray.from(k.keys())
- HAMT is the fastest choice for
fold
style, accumulation operations such as sum. - Native
Map
is fastest for transient operations, butImmutable
orHamt+
perform best of these libraries performance when a mix of transient and non-transient operations are used. - Hamt+ does have a small amount of overhead compared to regular Hamt, but performs much better when transient mutation can be used.
hashtrie - 0.2.2
hamt - 2.2.2
hamt_plus - 1.0.1
mori - 0.3.2
persistent-hash-trie - 0.4.2
immutable – 3.8.1
Get Nth
Native Object(10) : 28974807.90 +/- 0.42% op/s
Native Map(10) : 27120644.03 +/- 0.43% op/s
Hashtrie(10) : 14973683.83 +/- 0.18% op/s
Hamt(10) : 15757461.35 +/- 0.16% op/s
Hamt+(10) : 14753419.94 +/- 0.21% op/s
Mori(10) : 12573273.19 +/- 0.42% op/s
Immutable(10) : 14585838.78 +/- 0.25% op/s
Native Object(100) : 39607833.52 +/- 1.64% op/s
Native Map(100) : 22107935.96 +/- 0.42% op/s
Hashtrie(100) : 12059200.40 +/- 0.37% op/s
Hamt(100) : 12346282.20 +/- 1.05% op/s
Hamt+(100) : 12142017.69 +/- 0.64% op/s
Mori(100) : 12043487.55 +/- 0.57% op/s
Immutable(100) : 11303593.85 +/- 0.46% op/s
Native Object(1000) : 30413281.22 +/- 0.61% op/s
Native Map(1000) : 16087248.33 +/- 0.62% op/s
Hashtrie(1000) : 9270221.45 +/- 0.51% op/s
Hamt(1000) : 9972285.43 +/- 0.56% op/s
Hamt+(1000) : 9645216.60 +/- 0.48% op/s
Mori(1000) : 3333606.10 +/- 9.32% op/s
Immutable(1000) : 9255366.36 +/- 0.36% op/s
Native Object(10000) : 19207893.44 +/- 2.96% op/s
Native Map(10000) : 11906981.46 +/- 0.44% op/s
Hashtrie(10000) : 6138321.64 +/- 3.22% op/s
Hamt(10000) : 7036643.41 +/- 1.45% op/s
Hamt+(10000) : 6601570.56 +/- 1.29% op/s
Mori(10000) : 2745792.08 +/- 8.33% op/s
Immutable(10000) : 6127281.19 +/- 0.71% op/s
Native Object(100000) : 6522971.72 +/- 2.89% op/s
Native Map(100000) : 6273755.55 +/- 4.34% op/s
Hashtrie(100000) : 2007566.23 +/- 1.71% op/s
Hamt(100000) : 2272403.57 +/- 2.58% op/s
Hamt+(100000) : 2219278.75 +/- 1.67% op/s
Mori(100000) : 1565610.51 +/- 5.69% op/s
Immutable(100000) : 1759526.37 +/- 2.76% op/s
Put Nth
Native Object(10) : 844619.94 +/- 0.25% op/s
Native Map(10) : 1314589.24 +/- 0.50% op/s
Hashtrie(10) : 5005230.97 +/- 0.62% op/s
Hamt(10) : 7649050.96 +/- 11.00% op/s
Hamt+(10) : 4929251.89 +/- 9.77% op/s
Mori(10) : 3321039.16 +/- 0.71% op/s
Immutable(10) : 6088070.53 +/- 9.54% op/s
Native Object(100) : 38178.63 +/- 0.19% op/s
Native Map(100) : 138551.80 +/- 0.38% op/s
Hashtrie(100) : 4131956.44 +/- 0.56% op/s
Hamt(100) : 5195206.71 +/- 8.85% op/s
Hamt+(100) : 3388194.96 +/- 8.15% op/s
Mori(100) : 5815332.54 +/- 0.72% op/s
Immutable(100) : 4001976.76 +/- 8.11% op/s
Native Object(1000) : 3419.02 +/- 0.26% op/s
Native Map(1000) : 13345.61 +/- 0.71% op/s
Hashtrie(1000) : 3314365.79 +/- 1.00% op/s
Hamt(1000) : 3896640.86 +/- 8.37% op/s
Hamt+(1000) : 2661402.73 +/- 6.96% op/s
Mori(1000) : 3926763.48 +/- 0.98% op/s
Immutable(1000) : 2962506.32 +/- 6.83% op/s
Native Object(10000) : 287.07 +/- 2.96% op/s
Native Map(10000) : 1008.17 +/- 0.77% op/s
Hashtrie(10000) : 3071999.08 +/- 4.46% op/s
Hamt(10000) : 3636902.95 +/- 8.87% op/s
Hamt+(10000) : 2694014.20 +/- 6.82% op/s
Mori(10000) : 2205291.76 +/- 0.29% op/s
Immutable(10000) : 3013100.55 +/- 6.69% op/s
Native Object(100000) : 16.14 +/- 8.04% op/s
Native Map(100000) : 63.97 +/- 9.33% op/s
Hashtrie(100000) : 2558558.83 +/- 0.68% op/s
Hamt(100000) : 2823760.74 +/- 6.86% op/s
Hamt+(100000) : 2208812.07 +/- 5.39% op/s
Mori(100000) : 3116268.23 +/- 1.77% op/s
Immutable(100000) : 2424023.46 +/- 7.03% op/s
Put N
Native Object(10) : 213470.35 +/- 0.97% op/s
Native Map(10) : 232189.14 +/- 0.24% op/s
Hashtrie(10) : 559635.86 +/- 0.43% op/s
Hamt(10) : 1557228.23 +/- 1.61% op/s
Hamt+(10) : 624835.87 +/- 0.58% op/s
Mori(10) : 452871.51 +/- 0.61% op/s
Immutable(10) : 555858.54 +/- 0.65% op/s
Native Object(100) : 717.79 +/- 0.21% op/s
Native Map(100) : 2604.31 +/- 0.55% op/s
Hashtrie(100) : 41734.29 +/- 1.72% op/s
Hamt(100) : 72196.86 +/- 0.48% op/s
Hamt+(100) : 42046.94 +/- 1.79% op/s
Mori(100) : 55071.42 +/- 0.55% op/s
Immutable(100) : 50888.59 +/- 1.63% op/s
Native Object(1000) : 6.81 +/- 0.64% op/s
Native Map(1000) : 27.84 +/- 0.25% op/s
Hashtrie(1000) : 3452.02 +/- 1.64% op/s
Hamt(1000) : 4708.97 +/- 0.42% op/s
Hamt+(1000) : 3238.73 +/- 0.28% op/s
Mori(1000) : 2250.95 +/- 1.56% op/s
Immutable(1000) : 3915.16 +/- 0.44% op/s
Native Object(10000) : 0.06 +/- 0.78% op/s
Native Map(10000) : 0.25 +/- 0.33% op/s
Hashtrie(10000) : 258.82 +/- 1.06% op/s
Hamt(10000) : 357.25 +/- 0.83% op/s
Hamt+(10000) : 243.51 +/- 1.91% op/s
Mori(10000) : 188.37 +/- 1.88% op/s
Immutable(10000) : 259.72 +/- 2.20% op/s
Put N (transient)
Native Object(10) : 6355936.28 +/- 0.53% op/s
Native Map(10) : 2141761.58 +/- 0.94% op/s
Hamt(10) : 2391048.45 +/- 0.63% op/s
Hamt+(10) : 715025.40 +/- 0.97% op/s
Mori(10) : 372014.92 +/- 0.26% op/s
Immutable(10) : 592039.71 +/- 0.91% op/s
Native Object(100) : 225029.85 +/- 0.37% op/s
Native Map(100) : 253513.35 +/- 1.31% op/s
Hamt(100) : 100329.53 +/- 0.78% op/s
Hamt+(100) : 59642.00 +/- 1.11% op/s
Mori(100) : 10262.92 +/- 0.50% op/s
Immutable(100) : 74537.29 +/- 1.43% op/s
Native Object(1000) : 17409.89 +/- 1.06% op/s
Native Map(1000) : 22852.62 +/- 1.18% op/s
Hamt(1000) : 6399.83 +/- 1.07% op/s
Hamt+(1000) : 5109.15 +/- 1.08% op/s
Mori(1000) : 739.91 +/- 0.29% op/s
Immutable(1000) : 6750.34 +/- 0.87% op/s
Native Object(10000) : 1847.74 +/- 0.14% op/s
Native Map(10000) : 1762.05 +/- 0.91% op/s
Hamt(10000) : 454.53 +/- 1.28% op/s
Hamt+(10000) : 454.62 +/- 1.43% op/s
Mori(10000) : 71.28 +/- 0.33% op/s
Immutable(10000) : 585.08 +/- 1.32% op/s
Remove Nth
Native Object(10) : 554062.84 +/- 1.80% op/s
Native Map(10) : 1185616.11 +/- 0.50% op/s
Hashtrie(10) : 5119889.79 +/- 4.34% op/s
Hamt(10) : 7720252.40 +/- 0.72% op/s
Hamt+(10) : 6817854.59 +/- 3.88% op/s
Mori(10) : 6455392.22 +/- 0.65% op/s
Immutable(10) : 6229824.51 +/- 3.75% op/s
Native Object(100) : 37432.28 +/- 0.68% op/s
Native Map(100) : 137293.87 +/- 1.37% op/s
Hashtrie(100) : 4128467.71 +/- 3.95% op/s
Hamt(100) : 4973813.05 +/- 2.46% op/s
Hamt+(100) : 4364941.74 +/- 3.88% op/s
Mori(100) : 5693296.53 +/- 0.49% op/s
Immutable(100) : 4024498.82 +/- 4.21% op/s
Native Object(1000) : 3470.43 +/- 0.25% op/s
Native Map(1000) : 13822.13 +/- 3.69% op/s
Hashtrie(1000) : 3111371.11 +/- 0.63% op/s
Hamt(1000) : 3582435.31 +/- 4.32% op/s
Hamt+(1000) : 3250335.01 +/- 0.82% op/s
Mori(1000) : 2224709.88 +/- 6.70% op/s
Immutable(1000) : 2910640.42 +/- 0.48% op/s
Native Object(10000) : 306.72 +/- 0.23% op/s
Native Map(10000) : 1106.76 +/- 0.47% op/s
Hashtrie(10000) : 2404360.56 +/- 1.13% op/s
Hamt(10000) : 2976699.28 +/- 0.86% op/s
Hamt+(10000) : 2524228.58 +/- 4.10% op/s
Mori(10000) : 1784297.01 +/- 6.08% op/s
Immutable(10000) : 2208910.94 +/- 4.49% op/s
Native Object(100000) : 15.69 +/- 4.40% op/s
Native Map(100000) : 54.09 +/- 11.05% op/s
Hashtrie(100000) : 1133440.33 +/- 0.83% op/s
Hamt(100000) : 1320793.33 +/- 1.25% op/s
Hamt+(100000) : 1196216.46 +/- 1.87% op/s
Mori(100000) : 1093117.58 +/- 2.14% op/s
Immutable(100000) : 951182.37 +/- 2.08% op/s
Remove N
Native Object(10) : 75150.43 +/- 14.47% op/s
Native Map(10) : 120758.65 +/- 0.65% op/s
Hashtrie(10) : 893133.18 +/- 0.83% op/s
Hamt(10) : 1297110.23 +/- 0.80% op/s
Hamt+(10) : 1059784.36 +/- 0.87% op/s
Mori(10) : 1000958.83 +/- 1.11% op/s
Immutable(10) : 908096.05 +/- 0.41% op/s
Native Object(100) : 372.02 +/- 0.62% op/s
Native Map(100) : 1355.08 +/- 0.73% op/s
Hashtrie(100) : 57451.56 +/- 0.55% op/s
Hamt(100) : 68918.19 +/- 1.91% op/s
Hamt+(100) : 63600.45 +/- 0.91% op/s
Mori(100) : 72690.65 +/- 2.45% op/s
Immutable(100) : 59392.95 +/- 0.56% op/s
Native Object(1000) : 3.44 +/- 2.06% op/s
Native Map(1000) : 14.29 +/- 0.85% op/s
Hashtrie(1000) : 3875.06 +/- 0.37% op/s
Hamt(1000) : 4838.57 +/- 1.85% op/s
Hamt+(1000) : 4117.35 +/- 0.42% op/s
Mori(1000) : 2904.35 +/- 2.57% op/s
Immutable(1000) : 4223.82 +/- 1.55% op/s
Native Object(10000) : 0.03 +/- 0.82% op/s
Native Map(10000) : 0.11 +/- 0.32% op/s
Hashtrie(10000) : 250.06 +/- 1.05% op/s
Hamt(10000) : 355.14 +/- 1.93% op/s
Hamt+(10000) : 306.05 +/- 1.39% op/s
Mori(10000) : 217.79 +/- 3.15% op/s
Immutable(10000) : 314.68 +/- 0.22% op/s
Remove N (transient)
Native Assign(10) : 722527.06 +/- 0.77% op/s
Native Map(10) : 1046807.56 +/- 0.24% op/s
Hamt(10) : 1411581.78 +/- 0.31% op/s
Hamt+(10) : 856557.53 +/- 1.05% op/s
Mori(10) : 457271.38 +/- 0.47% op/s
Immutable(10) : 1041072.84 +/- 1.17% op/s
Native Assign(100) : 34632.17 +/- 0.25% op/s
Native Map(100) : 113397.13 +/- 1.14% op/s
Hamt(100) : 73017.79 +/- 1.68% op/s
Hamt+(100) : 77114.35 +/- 0.29% op/s
Mori(100) : 43091.93 +/- 0.77% op/s
Immutable(100) : 85791.46 +/- 0.50% op/s
Native Assign(1000) : 3042.80 +/- 0.54% op/s
Native Map(1000) : 10073.65 +/- 1.11% op/s
Hamt(1000) : 4835.00 +/- 0.64% op/s
Hamt+(1000) : 6545.06 +/- 0.95% op/s
Mori(1000) : 2447.39 +/- 1.21% op/s
Immutable(1000) : 7388.84 +/- 1.06% op/s
Native Assign(10000) : 281.11 +/- 0.73% op/s
Native Map(10000) : 865.82 +/- 0.86% op/s
Hamt(10000) : 348.95 +/- 1.17% op/s
Hamt+(10000) : 491.87 +/- 1.60% op/s
Mori(10000) : 216.97 +/- 1.98% op/s
Immutable(10000) : 531.93 +/- 0.80% op/s
Count
Native Object(10) : 64864734.85 +/- 0.71% op/s
Native Map(10) : 261425175.93 +/- 0.81% op/s
Hashtrie(10) : 5416247.07 +/- 0.66% op/s
Hamt(10) : 609334793.82 +/- 19.69% op/s
Hamt+(10) : 151481940.70 +/- 1.05% op/s
Mori(10) : 187799315.97 +/- 0.40% op/s
Immutable(10) : 644709859.31 +/- 17.78% op/s
Native Object(100) : 490535.38 +/- 0.18% op/s
Native Map(100) : 118518525.07 +/- 0.89% op/s
Hashtrie(100) : 0.00 +/- 0.00% op/s
Hamt(100) : 473634317.93 +/- 23.99% op/s
Hamt+(100) : 141823412.92 +/- 1.57% op/s
Mori(100) : 141302556.76 +/- 3.12% op/s
Immutable(100) : 158222206.63 +/- 1.35% op/s
Native Object(1000) : 21978.45 +/- 1.55% op/s
Native Map(1000) : 131411979.14 +/- 4.63% op/s
Hashtrie(1000) : 0.00 +/- 0.00% op/s
Hamt(1000) : 140556172.21 +/- 2.28% op/s
Hamt+(1000) : 178599942.25 +/- 6.97% op/s
Mori(1000) : 123193130.18 +/- 1.09% op/s
Immutable(1000) : 156770096.53 +/- 1.42% op/s
Native Object(10000) : 1338.75 +/- 0.19% op/s
Native Map(10000) : 114825267.23 +/- 0.85% op/s
Hashtrie(10000) : 0.00 +/- 0.00% op/s
Hamt(10000) : 175028408.43 +/- 1.64% op/s
Hamt+(10000) : 146323593.74 +/- 0.93% op/s
Mori(10000) : 123274851.58 +/- 1.14% op/s
Immutable(10000) : 181081867.50 +/- 1.98% op/s
Sum
Native Object(10) : 5037860.41 +/- 0.49% op/s
Native Map(10) : 2847825.55 +/- 0.38% op/s
Hashtrie(10) : 0.00 +/- 0.00% op/s
Hamt(10) : 13401619.37 +/- 1.04% op/s
Hamt+(10) : 8772658.01 +/- 0.48% op/s
Mori(10) : 7090215.40 +/- 0.48% op/s
Immutable(10) : 3377835.74 +/- 0.48% op/s
Native Object(100) : 208603.43 +/- 1.21% op/s
Native Map(100) : 422837.95 +/- 0.37% op/s
Hashtrie(100) : 0.00 +/- 0.00% op/s
Hamt(100) : 749374.54 +/- 0.97% op/s
Hamt+(100) : 679730.32 +/- 0.52% op/s
Mori(100) : 1041577.41 +/- 0.44% op/s
Immutable(100) : 421781.11 +/- 0.37% op/s
Native Object(1000) : 13052.63 +/- 1.05% op/s
Native Map(1000) : 43912.23 +/- 0.41% op/s
Hashtrie(1000) : 0.00 +/- 0.00% op/s
Hamt(1000) : 65621.88 +/- 1.20% op/s
Hamt+(1000) : 55285.53 +/- 0.20% op/s
Mori(1000) : 71965.04 +/- 0.25% op/s
Immutable(1000) : 34497.16 +/- 0.25% op/s
Native Object(10000) : 918.39 +/- 0.89% op/s
Native Map(10000) : 4490.63 +/- 0.10% op/s
Hashtrie(10000) : 0.00 +/- 0.00% op/s
Hamt(10000) : 6640.59 +/- 0.89% op/s
Hamt+(10000) : 6080.95 +/- 0.40% op/s
Mori(10000) : 8161.07 +/- 0.30% op/s
Immutable(10000) : 4072.33 +/- 0.78% op/s
Keys
Native Object(10) : 57164152.43 +/- 1.68% op/s
Native Map(10) : 864189.14 +/- 0.38% op/s
Hashtrie(10) : 4382646.88 +/- 0.90% op/s
Hamt(10) : 932758.09 +/- 0.25% op/s
Hamt fold(10) : 8864046.47 +/- 1.41% op/s
Hamt+(10) : 882688.30 +/- 0.37% op/s
Hamt+ fold(10) : 3977816.86 +/- 0.92% op/s
Mori(10) : 1162858.60 +/- 0.61% op/s
Immutable(10) : 681323.85 +/- 4.17% op/s
Native Object(100) : 433085.69 +/- 0.45% op/s
Native Map(100) : 107254.36 +/- 0.26% op/s
Hashtrie(100) : 0.00 +/- 0.00% op/s
Hamt(100) : 101415.02 +/- 0.48% op/s
Hamt fold(100) : 373729.87 +/- 0.40% op/s
Hamt+(100) : 94519.29 +/- 1.59% op/s
Hamt+ fold(100) : 349389.22 +/- 0.37% op/s
Mori(100) : 69942.43 +/- 0.77% op/s
Immutable(100) : 174370.09 +/- 2.01% op/s
Native Object(1000) : 21716.96 +/- 1.33% op/s
Native Map(1000) : 11022.24 +/- 0.41% op/s
Hashtrie(1000) : 0.00 +/- 0.00% op/s
Hamt(1000) : 9835.78 +/- 0.43% op/s
Hamt fold(1000) : 34322.81 +/- 0.30% op/s
Hamt+(1000) : 9296.36 +/- 0.26% op/s
Hamt+ fold(1000) : 32671.69 +/- 0.89% op/s
Mori(1000) : 4825.12 +/- 0.74% op/s
Immutable(1000) : 18574.48 +/- 1.45% op/s
Native Object(10000) : 1329.48 +/- 0.86% op/s
Native Map(10000) : 1123.76 +/- 0.51% op/s
Hashtrie(10000) : 0.00 +/- 0.00% op/s
Hamt(10000) : 1062.94 +/- 1.55% op/s
Hamt fold(10000) : 3546.25 +/- 0.47% op/s
Hamt+(10000) : 996.29 +/- 1.12% op/s
Hamt+ fold(10000) : 3466.11 +/- 0.35% op/s
Mori(10000) : 454.89 +/- 1.57% op/s
Immutable(10000) : 2170.35 +/- 0.26% op/s