Last active
August 22, 2021 12:16
-
-
Save petrounias/afa0ff32cc6b3adcf3a7b994119d8512 to your computer and use it in GitHub Desktop.
Clojure safe merge performance
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(require '[criterium.core :as crit]) | |
; figuring out the most performant way to merge two maps with only non-nil values in the right hand map, | |
; without failing for `false` values: | |
; | |
; (safe-merge {:foo true :bar 4} {:foo false :bar nil}) | |
; => {:foo false, :bar 4} | |
; | |
; ordered by decreasing execution time mean | |
(defn discard-nils-with-remove | |
[record] | |
(into {} (remove (comp nil? second) record))) | |
(def safe-merge-with-remove | |
(fn [left right] | |
(merge left (discard-nils-with-remove right)))) | |
(crit/quick-bench (safe-merge-with-remove {:foo true :bar 4} {:foo false :bar nil})) | |
;Evaluation count : 837252 in 6 samples of 139542 calls. | |
;Execution time mean : 716,944000 ns | |
;Execution time std-deviation : 6,620577 ns | |
;Execution time lower quantile : 712,552730 ns ( 2,5%) | |
;Execution time upper quantile : 728,307484 ns (97,5%) | |
;Overhead used : 1,593551 ns | |
(defn discard-nils-with-dissoc | |
[record] | |
(apply dissoc | |
record | |
(for [[k v] record :when (nil? v)] k))) | |
(def safe-merge-with-dissoc | |
(fn [left right] | |
(merge left (discard-nils-with-dissoc right)))) | |
(crit/quick-bench (safe-merge-with-dissoc {:foo true :bar 4} {:foo false :bar nil})) | |
;Evaluation count : 1277178 in 6 samples of 212863 calls. | |
;Execution time mean : 489,711185 ns | |
;Execution time std-deviation : 40,664672 ns | |
;Execution time lower quantile : 467,307104 ns ( 2,5%) | |
;Execution time upper quantile : 558,916085 ns (97,5%) | |
;Overhead used : 1,593551 ns | |
(defn discard-nils-with-merge | |
[record] | |
(apply merge (for [[k v] record :when (not (nil? v))] {k v}))) | |
(def safe-merge-with-merge | |
(fn [left right] | |
(merge left (discard-nils-with-merge right)))) | |
(crit/quick-bench (safe-merge-with-merge {:foo true :bar 4} {:foo false :bar nil})) | |
;Evaluation count : 1393698 in 6 samples of 232283 calls. | |
;Execution time mean : 430,248286 ns | |
;Execution time std-deviation : 2,328043 ns | |
;Execution time lower quantile : 428,329004 ns ( 2,5%) | |
;Execution time upper quantile : 433,656449 ns (97,5%) | |
;Overhead used : 1,593551 ns | |
(require '[clojure.core.match :refer [match]]) | |
(defn discard-nils-with-match [a b] | |
(match [a b] | |
[_ nil] a | |
:else b)) | |
(def safe-merge-with-match | |
(partial merge-with discard-nils-with-match)) | |
(crit/quick-bench (safe-merge-with-match {:foo true :bar 4} {:foo false :bar nil})) | |
;Evaluation count : 1775166 in 6 samples of 295861 calls. | |
;Execution time mean : 339,427178 ns | |
;Execution time std-deviation : 3,205639 ns | |
;Execution time lower quantile : 336,055550 ns ( 2,5%) | |
;Execution time upper quantile : 343,214908 ns (97,5%) | |
;Overhead used : 1,593551 ns | |
(defn discard-nils | |
[a b] | |
(if (nil? b) a b)) | |
(def safe-merge | |
(partial merge-with discard-nils)) | |
(crit/quick-bench (safe-merge {:foo true :bar 4} {:foo false :bar nil})) | |
;Evaluation count : 1348296 in 6 samples of 224716 calls. | |
;Execution time mean : 332,508236 ns | |
;Execution time std-deviation : 4,311911 ns | |
;Execution time lower quantile : 327,409726 ns ( 2,5%) | |
;Execution time upper quantile : 337,967775 ns (97,5%) | |
;Overhead used : 1,593551 ns | |
(defn assoc-some | |
([m k v] | |
(if (nil? v) m (assoc m k v))) | |
([m k v & kvs] | |
(reduce | |
(fn [m [k v]] (assoc-some m k v)) | |
(assoc-some m k v) | |
(partition 2 kvs)))) | |
(def safe-merge-with-assoc | |
(fn [left right] | |
(reduce (fn [l [k v]] (assoc-some l k v)) left right))) | |
(crit/quick-bench (safe-merge-with-assoc {:foo true :bar 4} {:foo false :bar nil})) | |
;Evaluation count : 2765952 in 6 samples of 460992 calls. | |
;Execution time mean : 156,734179 ns | |
;Execution time std-deviation : 3,658107 ns | |
;Execution time lower quantile : 153,871837 ns ( 2,5%) | |
;Execution time upper quantile : 162,657836 ns (97,5%) | |
;Overhead used : 1,593551 ns | |
(def safe-merge-with-assoc-direct | |
(fn [left right] | |
(reduce (fn [left [k v]] (if (nil? v) left (assoc left k v))) left right))) | |
(crit/quick-bench (safe-merge-with-assoc-direct {:foo true :bar 4} {:foo false :bar nil})) | |
;Evaluation count : 2709996 in 6 samples of 451666 calls. | |
;Execution time mean : 138,728946 ns | |
;Execution time std-deviation : 3,859391 ns | |
;Execution time lower quantile : 136,412854 ns ( 2,5%) | |
;Execution time upper quantile : 145,326409 ns (97,5%) | |
;Overhead used : 1,593551 ns |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment