The following is super fast.
(let [a (atom {})]
(doall (map #(swap! a merge {% 1}) (range 10000))) (println @a))
But if add partial, then is so slow. The result return by the code should be same,right? why does the performance diff so much?
(let [a (atom {})]
(doall (map #(swap! a (partial merge {% 1})) (range 10000))) (println @a))
(partial f a)
and #(f a %)
are actually quite different.
No matter the definition of f
, you are allowed to provide any number of arguments to the partially applied function, and the runtime will put them in a list and use apply
to get the result. So, no matter what, you have a short lived list constructed every time you use a function constructed with partial
. On the other hand, #()
creates a new class, and if you use an older JVM that segregates permgen from regular heap, this can become an issue as you use up more and more of the dedicated memory for classes.
Even if @noisesmith answer is right, the performance problem does not come from partial
.
The problem is more trivial: it is only the order in which the parameters are passed to merge
.
In #(swap! a merge {% 1})
the atom is passed as the first parameter to merge
. At each step, only {% 1}
is conjoined to the atom growing map.
In #(swap! a (partial merge {% 1}))
, the atom is passed as second parameter to merge
and at each step all elements of the atom a
are conjoined to {% 1}
.
Let's try a test with merge'
that call merge
, reversing the parameters. The map on which all elements from other maps are conjoined is the last one :
(defn merge' [& maps]
(apply merge (reverse maps)))
(require '[criterium.core :as c])
(c/quick-bench
(let [a (atom {})]
(dorun (map #(swap! a merge {% 1}) (range 10000))) ))
=> Execution time mean : 4.990763 ms
(c/quick-bench
(let [a (atom {})]
(dorun (map #(swap! a (partial merge' {% 1})) (range 10000))) ))
=> Execution time mean : 7.168238 ms
(c/quick-bench
(let [a (atom {})]
(dorun (map #(swap! a (partial merge {% 1})) (range 10000))) ))
=> Execution time mean : 10.610342 sec
The performances with merge
and (partial merge')
are comparable. (partial merge)
is effectively awful.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With