2024 年 Clojure 状况调查 中分享您的想法!

欢迎!请参阅 关于 页面了解更多有关此功能的详细信息。

0
Clojure
*描述*
有时需要对一系列值与一个值进行比较,Clojure 内部定义了一个用于此目的的谓词,它与简单的部分应用 = 相比有一些性能改进。

与 Rich 的先前讨论:https://groups.google.com/forum/#!topic/clojure-dev/0c-VNhEKVkI

*示例用法*

;;之前
(map (partial = 3) coll)
;;之后
(map (=to 3) coll)


*基准测试*

||测试||partial = 'foo||#(= 'foo %)||=to 'foo||
|小型同质集合|217ns|165ns|39ns|
|小型异质集合,|192ns|167ns|41ns|
|大型同质集合|66us|52us|8us|
|大型异质集合|82us|66us|27us|

*完整基准测试输出*

(use 'criterium.core)

(defn benchmark-f [f]
  (let [colls [['foo 'foo 'foo]
               [1 :foo 'foo]
               (doall (repeat 1e3 'foo))
               (doall (take 1e3 (cycle [1 :foo 'foo])))]]
    (doseq [c colls]
      (quick-bench (run! f c)))))

(benchmark-f (partial = 'foo))
警告:最终垃圾回收需要运行时 1.405293826432628 %
警告:最终垃圾回收需要运行时 10.202923149112559 %
评估计数:在 6 个样本中,共 519355 次调用,3116130 次
执行时间平均值:217.723199 纳秒
执行时间标准偏差:29.425291 纳秒
执行时间下四分位数:189.944710 纳秒 (2.5%)
执行时间上四分位数:261.717351 纳秒 (97.5%)
开销使用:1.863362 纳秒
警告:最终垃圾回收需要运行时 4.2579397621583315 %
评估计数:在 6 个样本中,共 523106 次调用,3138636 次
执行时间平均值:198.985418 纳秒
执行时间标准偏差:12.691848 纳秒
执行时间下四分位数:182.441245 纳秒 (2.5%)
执行时间上四分位数:207.839280 纳秒 (97.5%)
开销使用:1.863362 纳秒
警告:最终垃圾回收需要运行时 6.631646134523004 %
评估计数:在 6 个样本中,共 1673 次调用,10038 次
执行时间平均值:66.977712 微秒
执行时间标准偏差:10.411821 微秒
执行时间下四分位数:59.620690 微秒 (2.5%)
执行时间上四分位数:84.483254 微秒 (97.5%)
开销使用:1.863362 纳秒

发现 1 个离群值在 6 个样本中 (16.6667 %)
低严重  1 (16.6667 %)
离群值的方差:47.3059 % 方差受离群值适度膨胀
警告:最终垃圾回收需要运行时 5.272721959665122 %
评估计数:在 6 个样本中,共 1318 次调用,7908 次
执行时间平均值:82.588512 微秒
执行时间标准偏差:5.215537 微秒
执行时间下四分位数:75.977936 微秒 (2.5%)
执行时间上四分位数:86.849982 微秒 (97.5%)
开销使用:1.863362 纳秒


(benchmark-f #(= 'foo %))
警告:最终垃圾回收需要运行时 1.284421364203217 %
警告:最终的GC运行耗时占运行总时间的10.04376144830405%
评估次数:在6个样本中的607172次调用中有3643032次。
执行时间平均值:165.393131纳秒
执行时间标准差:1.041355纳秒
执行时间下四分位数:164.277060纳秒(2.5%)
执行时间上四分位数:166.849951纳秒(97.5%)
内存开销:1.605524纳秒
警告:最终的GC运行耗时占运行总时间的6.258680973295933%
评估次数:在6个样本中的597429次调用中有3584574次。
执行时间平均值:167.659014纳秒
执行时间标准差:3.821817纳秒
执行时间下四分位数:164.175156纳秒(2.5%)
执行时间上四分位数:173.210781纳秒(97.5%)
内存开销:1.605524纳秒

发现 1 个离群值在 6 个样本中 (16.6667 %)
低严重程度:1(16.6667%)
异常值方差:13.8889% 异常值导致方差适度膨胀
警告:最终的GC运行耗时占运行总时间的6.914389197005716%
评估次数:在6个样本中的1866次调用中有11196次。
执行时间平均值:52.593759微秒
执行时间标准差:834.220092纳秒



(基准-f (=to 'foo))
警告:最终的GC运行耗时占运行总时间的7.40391654943877%
评估次数:在6个样本中的2528178次调用中有15169068次。
执行时间平均值:39.937424纳秒
执行时间标准差:2.782661纳秒
执行时间下四分位数:37.393937纳秒(2.5%)
执行时间上四分位数:42.780432纳秒(97.5%)
开销使用:1.863362 纳秒
警告:最终的GC运行耗时占运行总时间的5.986859953402835%
评估次数:在6个样本中的2533332次调用中有15199992次。
执行时间平均值:41.229082纳秒
执行时间标准差:2.815533纳秒
执行时间下四分位数:37.371527纳秒(2.5%)
执行时间上四分位数:43.208673纳秒(97.5%)
开销使用:1.863362 纳秒
警告:最终的GC运行耗时占运行总时间的5.039484046472016%
评估次数:在6个样本中的11577次调用中有69462次。
执行时间平均值:8.976972微秒
执行时间标准差:587.089991纳秒
执行时间下四分位数:8.505317微秒(2.5%)
执行时间上四分位数:9.744296微秒(97.5%)
开销使用:1.863362 纳秒
警告:最终的GC运行耗时占运行总时间的5.773010947849351%
评估次数:在6个样本中的3892次调用中有23352次。
执行时间平均值:27.277376微秒
执行时间标准差:2.115666微秒
执行时间下四分位数:25.719322微秒(2.5%)
执行时间上四分位数:30.123547微秒(97.5%)
开销使用:1.863362 纳秒


*补丁*:0001-CLJ-1843-add-to-for-faster-equality-check-against-kn.patch

7 个答案

0

评论者:alexmiller

你看了(应用=3 coll)吗?只是好奇。

0

评论者:bronsa

Util/equivPred 相比于 Util/equiv 的优势在于,它可以自动推断提供的参数类型,避免了 Util/equiv 内部对于比较器类型进行多次实例检查的运行时开销。

0

评论者:alexmiller

你能否对这两种方法在 2-3 种集合大小上的差异进行量化?

0
评论由:bronsa_ 发表

以下是设置情况


(use 'criterium.core)

(defn =to [x]
  (let [pred (clojure.lang.Util/equivPred x)]
    (fn [y]
      (.equiv pred x y))))

(defn benchmark-f [f]
  (let [colls [['foo 'foo 'foo]
               [1 :foo 'foo]
               (doall (repeat 1e3 'foo))
               (doall (take 1e3 (cycle [1 :foo 'foo])))]]
    (doseq [c colls]
      (quick-bench (run! f c)))))

(benchmark-f (partial = 'foo)) 的结果为



WARNING: 最终GC所需运行时百分比:1.405293826432628 %
警告:最终垃圾回收需要运行时 10.202923149112559 %
评估计数:在 6 个样本中,共 519355 次调用,3116130 次
执行时间平均值:217.723199 纳秒
执行时间标准偏差:29.425291 纳秒
执行时间下四分位数:189.944710 纳秒 (2.5%)
执行时间上四分位数:261.717351 纳秒 (97.5%)
开销使用:1.863362 纳秒
警告:最终垃圾回收需要运行时 4.2579397621583315 %
评估计数:在 6 个样本中,共 523106 次调用,3138636 次
执行时间平均值:198.985418 纳秒
执行时间标准偏差:12.691848 纳秒
执行时间下四分位数:182.441245 纳秒 (2.5%)
执行时间上四分位数:207.839280 纳秒 (97.5%)
开销使用:1.863362 纳秒
警告:最终垃圾回收需要运行时 6.631646134523004 %
评估计数:在 6 个样本中,共 1673 次调用,10038 次
执行时间平均值:66.977712 微秒
执行时间标准偏差:10.411821 微秒
执行时间下四分位数:59.620690 微秒 (2.5%)
执行时间上四分位数:84.483254 微秒 (97.5%)
开销使用:1.863362 纳秒

发现 1 个离群值在 6 个样本中 (16.6667 %)
低严重  1 (16.6667 %)
离群值的方差:47.3059 % 方差受离群值适度膨胀
警告:最终垃圾回收需要运行时 5.272721959665122 %
评估计数:在 6 个样本中,共 1318 次调用,7908 次
执行时间平均值:82.588512 微秒
执行时间标准偏差:5.215537 微秒
执行时间下四分位数:75.977936 微秒 (2.5%)
执行时间上四分位数:86.849982 微秒 (97.5%)
开销使用:1.863362 纳秒


(benchmark-f (=to 'foo)) 的结果为


警告:最终的GC运行耗时占运行总时间的7.40391654943877%
评估次数:在6个样本中的2528178次调用中有15169068次。
执行时间平均值:39.937424纳秒
执行时间标准差:2.782661纳秒
执行时间下四分位数:37.393937纳秒(2.5%)
执行时间上四分位数:42.780432纳秒(97.5%)
开销使用:1.863362 纳秒
警告:最终的GC运行耗时占运行总时间的5.986859953402835%
评估次数:在6个样本中的2533332次调用中有15199992次。
执行时间平均值:41.229082纳秒
执行时间标准差:2.815533纳秒
执行时间下四分位数:37.371527纳秒(2.5%)
执行时间上四分位数:43.208673纳秒(97.5%)
开销使用:1.863362 纳秒
警告:最终的GC运行耗时占运行总时间的5.039484046472016%
评估次数:在6个样本中的11577次调用中有69462次。
执行时间平均值:8.976972微秒
执行时间标准差:587.089991纳秒
执行时间下四分位数:8.505317微秒(2.5%)
执行时间上四分位数:9.744296微秒(97.5%)
开销使用:1.863362 纳秒
警告:最终的GC运行耗时占运行总时间的5.773010947849351%
评估次数:在6个样本中的3892次调用中有23352次。
执行时间平均值:27.277376微秒
执行时间标准差:2.115666微秒
执行时间下四分位数:25.719322微秒(2.5%)
执行时间上四分位数:30.123547微秒(97.5%)
开销使用:1.863362 纳秒
0
评论由:bronsa_ 发表

使用 #(= 'foo %) 而不是 (partial = 'foo) 允许 = 内联,从而略微提高性能,但 =to 的性能仍有明显提升

警告:最终垃圾回收需要运行时 1.284421364203217 %
警告:最终的GC运行耗时占运行总时间的10.04376144830405%
评估次数:在6个样本中的607172次调用中有3643032次。
执行时间平均值:165.393131纳秒
执行时间标准差:1.041355纳秒
执行时间下四分位数:164.277060纳秒(2.5%)
执行时间上四分位数:166.849951纳秒(97.5%)
内存开销:1.605524纳秒
警告:最终的GC运行耗时占运行总时间的6.258680973295933%
评估次数:在6个样本中的597429次调用中有3584574次。
执行时间平均值:167.659014纳秒
执行时间标准差:3.821817纳秒
执行时间下四分位数:164.175156纳秒(2.5%)
执行时间上四分位数:173.210781纳秒(97.5%)
内存开销:1.605524纳秒

发现 1 个离群值在 6 个样本中 (16.6667 %)
低严重程度:1(16.6667%)
异常值方差:13.8889% 异常值导致方差适度膨胀
警告:最终的GC运行耗时占运行总时间的6.914389197005716%
评估次数:在6个样本中的1866次调用中有11196次。
执行时间平均值:52.593759微秒
执行时间标准差:834.220092纳秒
   运行时间下四分位数:51.510161 µs ( 2.5%)
   运行时间上四分位数:53.367649 µs (97.5%)
内存开销:1.605524纳秒
WARNING: 最终GC所需运行时百分比:6.179040224498723 %
计算次数:6样本中9162次调用。
             平均执行时间:66.527357 µs
    执行时间标准差:2.119652 µs
   运行时间下四分位数:65.308835 µs ( 2.5%)
   运行时间上四分位数:70.201570 µs (97.5%)
内存开销:1.605524纳秒


小型同构集合,*(partial = 'foo)*: 217ns, *#(= 'foo %)*: 165ns, *(=to 'foo)*: 39ns
小型异构集合,*(partial = 'foo)*: 192ns, *#(= 'foo %)*: 167ns, *(=to 'foo)*: 41ns
大型同构集合,*(partial = 'foo)*: 66us, *#(= 'foo %)*: 52us, *(=to 'foo)*: 8us
大型异构集合,*(partial = 'foo)*: 82us, *#(= 'foo %)*: 66us, *(=to 'foo)*: 27us
0

评论者:bronsa

这显然是几年前已经开始讨论的问题,Rich 也对此表示赞同 https://groups.google.com/forum/#!topic/clojure-dev/0c-VNhEKVkI

0
参考: https://clojure.atlassian.net/browse/CLJ-1843 (由 bronsa 报告)
...