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|

*完整基准测试输出*

(使用 'criterium.core)

(defn 基准测试-f [f]
  (let [colls [['foo 'foo 'foo]
              [1 :foo 'foo]
               (doall (重复 1e3 'foo))
               (doall (take 1e3 (cycle [1 :foo 'foo])))]]
    (doseq [c colls]
      (快速基准测试 (run! f c)))))

(基准测试-f (partial = 'foo))
WARNING: Final GC required 1.405293826432628 % of runtime
警告:最终 GC 需要 10.202923149112559 % 的运行时间
评估计数:3116130 在 6 个样本中的 519355 次调用。
执行时间平均:217.723199 ns
执行时间标准差:29.425291 ns
执行时间下四分位数:189.944710 ns ( 2.5%)
执行时间上四分位数:261.717351 ns (97.5%)
Overhead 使用:1.863362 ns
警告:最终 GC 需要 4.2579397621583315 % 的运行时间
评估计数:3138636 在 6 个样本中的 523106 次调用。
执行时间平均:198.985418 ns
执行时间标准差:12.691848 ns
执行时间下四分位数:182.441245 ns ( 2.5%)
执行时间上四分位数:207.839280 ns (97.5%)
Overhead 使用:1.863362 ns
警告:最终 GC 需要 6.631646134523004 % 的运行时间
评估计数:10038 在 6 个样本中的 1673 次调用。
执行时间平均:66.977712 µs
执行时间标准差:10.411821 µs
执行时间下四分位数:59.620690 µs ( 2.5%)
执行时间上四分位数:84.483254 µs (97.5%)
Overhead 使用:1.863362 ns

在 6 个样本中发现 1 个异常值 (16.6667 %)
low-severe  1 (16.6667 %)
Variance from outliers : 47.3059 % Variance is moderately inflated by outliers
警告:最终 GC 需要 5.272721959665122 % 的运行时间
评估计数:7908 在 6 个样本中的 1318 次调用。
执行时间平均:82.588512 µs
执行时间标准差:5.215537 µs
执行时间下四分位数:75.977936 µs ( 2.5%)
执行时间上四分位数:86.849982 µs (97.5%)
Overhead 使用:1.863362 ns


(基准测试-f #(= 'foo %))
警告:最后的垃圾回收占用了运行时的1.284421364203217 %
警告:最后的垃圾回收占用了运行时的10.04376144830405 %
评估次数:在607172次调用中的6个样本,共3643032次。
               执行时间平均值:165.393131纳秒
    执行时间标准差:1.041355纳秒
   执行时间的下四分位数:164.277060纳秒(2.5%)
   执行时间的上四分位数:166.849951纳秒(97.5%)
                  开销使用:1.605524纳秒
警告:最后的垃圾回收占用了运行时的6.258680973295933 %
评估次数:在597429次调用中的6个样本,共3584574次。
             执行时间平均值:167.659014纳秒
    执行时间标准差:3.821817纳秒
   执行时间的下四分位数:164.175156纳秒(2.5%)
   执行时间的上四分位数:173.210781纳秒(97.5%)
                  开销使用:1.605524纳秒

在 6 个样本中发现 1 个异常值 (16.6667 %)
   低严重程度     1(16.6667 %)
异常值方差:13.8889 % 异常值导致方差适度膨胀
警告:最后的垃圾回收占用了运行时的6.914389197005716 %
评估次数:在1866次调用中的6个样本,共11196次。
             执行时间平均值:52.593759微秒
    执行时间标准差:834.220092纳秒



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


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

7 个答案

0

评论者:alexmiller

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

0

评论由:bronsa发表

相比于Util/equiv,Util/equivPred的优势在于能够假设提供的参数类型,从而避免了在Util/equiv中需要进行的多次实例检查,这样可以降低内部决定使用哪个比较器的运行时成本

0

评论者:alexmiller

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

0
_评论由:bronsa发表_

以下为设置


(使用 'criterium.core)

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

(defn 基准测试-f [f]
  (let [colls [['foo 'foo 'foo]
              [1 :foo 'foo]
               (doall (重复 1e3 'foo))
               (doall (take 1e3 (cycle [1 :foo 'foo])))]]
    (doseq [c colls]
      (快速基准测试 (run! f c)))))

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



WARNING: Final GC required 1.405293826432628 % of runtime
警告:最终 GC 需要 10.202923149112559 % 的运行时间
评估计数:3116130 在 6 个样本中的 519355 次调用。
执行时间平均:217.723199 ns
执行时间标准差:29.425291 ns
执行时间下四分位数:189.944710 ns ( 2.5%)
执行时间上四分位数:261.717351 ns (97.5%)
Overhead 使用:1.863362 ns
警告:最终 GC 需要 4.2579397621583315 % 的运行时间
评估计数:3138636 在 6 个样本中的 523106 次调用。
执行时间平均:198.985418 ns
执行时间标准差:12.691848 ns
执行时间下四分位数:182.441245 ns ( 2.5%)
执行时间上四分位数:207.839280 ns (97.5%)
Overhead 使用:1.863362 ns
警告:最终 GC 需要 6.631646134523004 % 的运行时间
评估计数:10038 在 6 个样本中的 1673 次调用。
执行时间平均:66.977712 µs
执行时间标准差:10.411821 µs
执行时间下四分位数:59.620690 µs ( 2.5%)
执行时间上四分位数:84.483254 µs (97.5%)
Overhead 使用:1.863362 ns

在 6 个样本中发现 1 个异常值 (16.6667 %)
low-severe  1 (16.6667 %)
Variance from outliers : 47.3059 % Variance is moderately inflated by outliers
警告:最终 GC 需要 5.272721959665122 % 的运行时间
评估计数:7908 在 6 个样本中的 1318 次调用。
执行时间平均:82.588512 µs
执行时间标准差:5.215537 µs
执行时间下四分位数:75.977936 µs ( 2.5%)
执行时间上四分位数:86.849982 µs (97.5%)
Overhead 使用:1.863362 ns


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


警告:最后的垃圾回收占用了运行时的7.40391654943877 %
评估次数:在2528178次调用中的6个样本,共15169068次。
执行时间平均值:39.937424纳秒
执行时间标准差:2.782661纳秒
执行时间的下四分位数:37.393937纳秒(2.5%)
执行时间的上四分位数:42.780432纳秒(97.5%)
Overhead 使用:1.863362 ns
警告:最后的垃圾回收占用了运行时的5.986859953402835 %
评估次数:在2533332次调用中的6个样本,共15199992次。
执行时间平均值:41.229082纳秒
执行时间标准差:2.815533纳秒
执行时间的下四分位数:37.371527纳秒(2.5%)
执行时间的上四分位数:43.208673纳秒(97.5%)
Overhead 使用:1.863362 ns
警告:最后的垃圾回收占用了运行时的5.039484046472016 %
评估次数:在11577次调用中的6个样本,共69462次。
执行时间平均值:8.976972微秒
执行时间标准差:587.089991纳秒
执行时间的下四分位数:8.505317微秒(2.5%)
执行时间的上四分位数:9.744296微秒(97.5%)
Overhead 使用:1.863362 ns
警告:最后的垃圾回收占用了运行时的5.773010947849351 %
评估次数:在3892次调用中的6个样本,共23352次。
执行时间平均值:27.277376微秒
执行时间标准差:2.115666微秒
执行时间的下四分位数:25.719322微秒(2.5%)
执行时间的上四分位数:30.123547微秒(97.5%)
Overhead 使用:1.863362 ns
0
_评论由:bronsa发表_

使用#(= 'foo %)而不是(partial = 'foo)可以允许内联=并使性能略有改进,但=to仍然显著优于其他方法

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

在 6 个样本中发现 1 个异常值 (16.6667 %)
   低严重程度     1(16.6667 %)
异常值方差:13.8889 % 异常值导致方差适度膨胀
警告:最后的垃圾回收占用了运行时的6.914389197005716 %
评估次数:在1866次调用中的6个样本,共11196次。
             执行时间平均值:52.593759微秒
    执行时间标准差:834.220092纳秒
   执行时间下限:51.510161 µs ( 2.5%)
   执行时间上限:53.367649 µs (97.5%)
                  开销使用:1.605524纳秒
WARNING: Final GC required 6.179040224498723 % of runtime
评估次数: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
...