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))
WARNING: 最终 GC 需要了 1.405293826432628 % 的运行时间
WARNING: 最终 GC 需要了 10.202923149112559 % 的运行时间
评估计数:3116130 在 6 个样本中的 519355 次调用。
平均执行时间:217.723199 纳秒
执行时间标准差:29.425291 纳秒
执行时间下四分位数:189.944710 纳秒 ( 2.5%)
执行时间上四分位数:261.717351 纳秒 (97.5%)
使用的开销:1.863362 纳秒
WARNING: 最终 GC 需要了 4.2579397621583315 % 的运行时间
评估计数:3138636 在 6 个样本中的 523106 次调用。
平均执行时间:198.985418 纳秒
执行时间标准差:12.691848 纳秒
执行时间下四分位数:182.441245 纳秒 ( 2.5%)
执行时间上四分位数:207.839280 纳秒 (97.5%)
使用的开销:1.863362 纳秒
WARNING: 最终 GC 需要了 6.631646134523004 % 的运行时间
评估计数:10038 在 6 个样本中的 1673 次调用。
平均执行时间:66.977712 微秒
执行时间标准差:10.411821 微秒
执行时间下四分位数:59.620690 微秒 ( 2.5%)
执行时间上四分位数:84.483254 微秒 (97.5%)
使用的开销:1.863362 纳秒

在 6 个样本中找到 1 个异常值 (16.6667 %)
低异常值  1 (16.6667 %)
异常值从方差中提取:47.3059 % 异常值导致方差适度膨胀
WARNING: 最终 GC 需要了 5.272721959665122 % 的运行时间
评估计数:7908 在 6 个样本中的 1318 次调用。
平均执行时间:82.588512 微秒
执行时间标准差:5.215537 微秒
执行时间下四分位数:75.977936 微秒 ( 2.5%)
执行时间上四分位数:86.849982 微秒 (97.5%)
使用的开销:1.863362 纳秒


(benchmark-f #(= 'foo %))
WARNING: 最终 GC 需要了 1.284421364203217 % 的运行时间
警告:最终GC占用了运行时间的10.04376144830405%。
评估次数:在6个样本中,共3643032次调用。
             平均执行时间:167.393131纳秒。
    执行时间标准差:1.041355纳秒。
   执行时间下四分位数:164.277060纳秒(2.5%)。
   执行时间上四分位数:166.849951纳秒(97.5%)。
                    开销:1.605524纳秒。
警告:最终GC占用了运行时间的6.258680973295933%。
评估次数:在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%,方差异常值影响中等。
警告:最终GC占用了运行时间的6.914389197005716%。
评估次数:在6个样本中,共11196次调用。
             平均执行时间:52.593759微秒。
    执行时间标准差:834.220092纳秒。



(benchmark-f (=to 'foo))
警告:最终GC占用了运行时间的7.40391654943877%。
评估次数:在6个样本中,共15169068次调用。
平均执行时间:39.937424纳秒。
执行时间标准差:2.782661纳秒。
执行时间下四分位数:37.393937纳秒(2.5%)。
执行时间上四分位数:42.780432纳秒(97.5%)。
使用的开销:1.863362 纳秒
警告:最终GC占用了运行时间的5.986859953402835%。
评估次数:在6个样本中,共15199992次调用。
平均执行时间:41.229082纳秒。
执行时间标准差:2.815533纳秒。
执行时间下四分位数:37.371527纳秒(2.5%)。
执行时间上四分位数:43.208673纳秒(97.5%)。
使用的开销:1.863362 纳秒
警告:最终GC占用了运行时间的5.039484046472016%。
评估次数:在6个样本中,共69462次调用。
平均执行时间:8.976972微秒。
执行时间标准差:587.089991纳秒。
执行时间下四分位数:8.505317微秒(2.5%)。
执行时间上四分位数:9.744296微秒(97.5%)。
使用的开销:1.863362 纳秒
警告:最终GC占用了运行时间的5.773010947849351%。
评估次数:在6个样本中,共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
by

评论由:alexmiller 提供

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

0

评论者:bronsa

与 Util/equiv 相比,Util/equivPred 的优势在于它可以假设提供的参数类型,避免了 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)))))

=to 'foo' 的基准结果为



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

在 6 个样本中找到 1 个异常值 (16.6667 %)
低异常值  1 (16.6667 %)
异常值从方差中提取:47.3059 % 异常值导致方差适度膨胀
WARNING: 最终 GC 需要了 5.272721959665122 % 的运行时间
评估计数:7908 在 6 个样本中的 1318 次调用。
平均执行时间:82.588512 微秒
执行时间标准差:5.215537 微秒
执行时间下四分位数:75.977936 微秒 ( 2.5%)
执行时间上四分位数:86.849982 微秒 (97.5%)
使用的开销:1.863362 纳秒


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


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

使用 #(= 'foo %) 而不是 (partial = 'foo) 可以让 = 进行内联,使性能略有提升,但 =to 的性能更为显著

WARNING: 最终 GC 需要了 1.284421364203217 % 的运行时间
警告:最终GC占用了运行时间的10.04376144830405%。
评估次数:在6个样本中,共3643032次调用。
             平均执行时间:167.393131纳秒。
    执行时间标准差:1.041355纳秒。
   执行时间下四分位数:164.277060纳秒(2.5%)。
   执行时间上四分位数:166.849951纳秒(97.5%)。
                    开销:1.605524纳秒。
警告:最终GC占用了运行时间的6.258680973295933%。
评估次数:在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%,方差异常值影响中等。
警告:最终GC占用了运行时间的6.914389197005716%。
评估次数:在6个样本中,共11196次调用。
             平均执行时间:52.593759微秒。
    执行时间标准差:834.220092纳秒。
   执行时间下四分位数:51.510161 微秒(2.5%)
   执行时间上四分位数:53.367649 微秒(97.5%)
                    开销:1.605524纳秒。
警告:最终 GC 所需时间为运行时间的 6.179040224498723 %
评估次数:9162,在 6 个样本中调用 1527 次
             执行时间均值:66.527357 微秒
   执行时间标准差:2.119652 微秒
   执行时间下四分位数:65.308835 微秒(2.5%)
   执行时间上四分位数:70.201570 微秒(97.5%)
                    开销:1.605524纳秒。


小同质集合,*(partial = 'foo)*:217 纳秒,*#(= 'foo %)*:165 纳秒,*(=to 'foo)*:39 纳秒
小异质集合,*(partial = 'foo)*:192 纳秒,*#(= 'foo %)*:167 纳秒,*(=to 'foo)*:41 纳秒
大同质集合,*(partial = 'foo)*:66 微秒,*#(= 'foo %)*:52 微秒,*(=to 'foo)*:8 微秒
大异质集合,*(partial = 'foo)*:82 微秒,*#(= 'foo %)*:66 微秒,*(=to 'foo)*:27 微秒
0

评论者:bronsa

显然,这是我们几年前已经讨论过的事情,Rich对此表示没问题。https://groups.google.com/forum/#!topic/clojure-dev/0c-VNhEKVkI

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