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

欢迎!请参阅关于页面以了解更多关于它是如何工作的信息。

0
Collections

c.c/hash 总是使用 hashCode 来生成 Java 集合的哈希值,这是与使用 Murmur3 的 Clojure 集合进行比较时的不兼容原因。

user> (== (hash (java.util.ArrayList. [1 2 3])) (hash [1 2 3])) false user> (= (java.util.ArrayList. [1 2 3]) [1 2 3]) true

修复方法之一是在 Util/hasheq 中添加一个特殊案例以适应 java.util.Collections,就像现在对 String 所做的那样。

关于这个主题的 Clojure 群组讨论链接:https://groups.google.com/forum/#!topic/clojure/dQhdwZsyIEw

43 个答案

0

stu 发表的评论:

我认为这个问题需要更多考虑,不应该阻挡 1.6 版本。

0

jafingerhut 发表的评论:

到 2014 年 3 月 20 日为止,最新的 Clojure master 上的 clj-1372.diff 和 clj-1372-2.diff 补丁未能干净地应用。我相信,在 2014 年 3 月 19 日的提交之前,它们是干净应用过的,唯一问题似乎是补丁上下文中的改变了行。鉴于关于是否需要这样修改的讨论,看起来在决定是否进行任何更改之前,需要更多的思考。

0

mikera 发表的评论:

这是一个相当糟糕的错误。它绝对需要修复。这并不是关于是否混合使用Clojure和Java集合是一个可能的用例的问题(恐怕不是...),而是关于提供人们可以依赖的一贯保证。

例如,现在我真的很不确定我所拥有的某些使用集合或映射的库函数是否损坏。我特别担心任何基于哈希值的对象缓存/记忆化/内部化的实现。这样的代码现在可能有非常糟糕的细微缺陷。

由于这些是库函数,我无法保证传入的对象类型,因此代码必须与所有可能的输入都兼容(或者我需要编写清晰的文档字符串,并在不支持输入时抛出异常)。

0
_评论由:michalmarczyk_发表

这个补丁(0001-CLJ-1372-consistent-hasheq-for-java.util.-List-Map-M.patch)让hasheq与java.util.{List,Map,Map.Entry,Set}中的=保持一致。它还将String的特殊处理(返回hashCode的hasheq)扩展到所有未处理的类型(以下对此有评论)。

它也在这里可用

https://github.com/michalmarczyk/clojure/tree/alien-hasheq-2

早期版本在这里

https://github.com/michalmarczyk/clojure/tree/alien-hasheq

如果我理解正确,需要基准测试的主要是clojure.lang.Util/hasheq给定Clojure类型的“调度时间”。因此,我重复哈希了同一个持久性哈希映射,因为这将仅测量IHashEq实例的调度时间。然后我运行了另一个基准测试,对PHM、字符串和长进行了哈希,并使用unchecked-add将结果相加。希望这是一个好的开始;我毫无疑问还需要进行更多基准测试。

结果让我有些意外:在我构建的这个基准测试中,PHM上的hasheq实际上比1.6.0稍微快一点;“添加三个hasheq”基准在1.6.0上稍微快一点。


;;; 1.6.0

;;; 注意:j.u.HM基准不相关
user=> (let [phm (apply hash-map (interleave (range 128) (range 128))) juhm (java.util.HashMap. phm)] #_(assert (= (hash phm) (hash juhm))) (c/bench (clojure.lang.Util/hasheq phm)) (c/bench (clojure.lang.Util/hasheq juhm)))
警告:最终GC消耗了1.24405836928592%的运行时间
评估次数:5549560980次,在60次样本中,每次调用92492683次。
             执行时间平均值:9.229881纳秒
    执行时间标准差:0.156716纳秒
   执行时间下四分位数:8.985994纳秒(2.5%)
   执行时间上四分位数:9.574039纳秒(97.5%)
                   过度使用:1.741068纳秒

在60个样本中发现了2个异常值(3.3333%)
   低严重     2 (3.3333%)
 异常值方差:6.2652%。方差略受异常值影响
评估次数:35647680次,在60个样本中,每次调用594128次。
             执行时间平均值:1.695145微秒
    执行时间标准差:20.186554纳秒
   执行时间下四分位数:1.670049微秒(2.5%)
   执行时间上四分位数:1.740329微秒(97.5%)
                   过度使用:1.741068纳秒

在60个样本中发现了2个异常值(3.3333%)
   低严重     2 (3.3333%)
 异常值方差:1.6389%。方差略受异常值影响
nil

user=> (let [phm (apply hash-map (interleave (range 128) (range 128))) juhm (java.util.HashMap. phm)] #_(assert (= (hash phm) (hash juhm))) (c/bench (unchecked-add (clojure.lang.Util/hasheq phm) (unchecked-add (clojure.lang.Util/hasheq "foo") (clojure.lang.Util/hasheq 123)))))
警告:最后垃圾回收需要占用运行时时间的 1.028614538339401 %。
评估次数:在60个样本中的17165805次调用,总计1029948300次。
             执行时间平均值:56.797488 纳秒
    执行时间标准偏差:0.732221 纳秒
   执行时间下四分位数:55.856731 纳秒(2.5%)
   执行时间上四分位数:58.469940 纳秒(97.5%)
                   开销:1.836671 纳秒

在60个样本中发现了1个异常值(1.6667%)
    低严重性     1(1.6667%)
 异常值方差:1.6389%。方差略受异常值影响
nil

;;; 补丁应用

user=> (let [phm (apply hash-map (interleave (range 128) (range 128))) juhm (java.util.HashMap. phm)] (assert (= (hash phm) (hash juhm))) (c/bench (clojure.lang.Util/hasheq phm)) (c/bench (clojure.lang.Util/hasheq juhm)))
评估次数:在60个样本中的92294978次调用,总计5537698680次。
             执行时间平均值:8.973200 纳秒
    执行时间标准偏差:0.157079 纳秒
   执行时间下四分位数:8.733544 纳秒(2.5%)
   执行时间上四分位数:9.289350 纳秒(97.5%)
                   开销:1.744772 纳秒
评估次数:在60个样本中的41360次调用,总计2481600次。
             执行时间平均值:24.287800 微秒
    执行时间标准偏差:288.124326 纳秒
   执行时间下四分位数:23.856445 微秒(2.5%)
   执行时间上四分位数:24.774097 微秒(97.5%)
                   开销:1.744772 纳秒
nil

user=> (let [phm (apply hash-map (interleave (range 128) (range 128))) juhm (java.util.HashMap. phm)] #_(assert (= (hash phm) (hash juhm))) (c/bench (unchecked-add (clojure.lang.Util/hasheq phm) (unchecked-add (clojure.lang.Util/hasheq "foo") (clojure.lang.Util/hasheq 123)))))
警告:最后垃圾回收需要占用运行时时间的 1.298136122909759 %。
评估次数:在60个样本中的15912525次调用,总计954751500次。
             执行时间平均值:61.681794 纳秒
    执行时间标准偏差:0.712110 纳秒
   执行时间下四分位数:60.622003 纳秒(2.5%)
   执行时间上四分位数:62.904801 纳秒(97.5%)
                   开销:1.744772 纳秒

在60个样本中发现了1个异常值(1.6667%)
    低严重性     1(1.6667%)
 异常值方差:1.6389%。方差略受异常值影响
nil


此外,早期可用的另一分支上的补丁并为字符串创建单独的分支。这使得实现IHashEq的对象的hasheq更快速,但“三个哈希”基准测试的速度减慢了大约2倍。
0

由 alexmiller 评论

为了清晰起见,请按照补丁名称引用此处附带的补丁,这样随着时间推移,我们就不必将附件时间与评论时间关联起来。

我对实现IHashEq的成本不太关心,因为它们应该不受影响,除了潜在的内联问题。我很好奇hasheq对这些达到末尾并支付所有检查费用的对象的成本。上面评论列表中的一些东西是一个好的起点——例如类、字符和Var(这可能在Var中解决)。

0

由 michalmarczyk 评论

好点子,我已经将上面的评论编辑为包括补丁名称。

感谢您提供的基准测试建议 -- 我将在大约6分钟内发布一些新的结果。

0

由 michalmarczyk 评论

首先,为了完整性,这里提供了一个新的补丁(0001-CLJ-1372-consistent-hasheq-for-java.util.-List-Map-M-alternative.patch),它不对未处理的类型执行额外的咕哝。在单个PHM的情况下要慢一些;详情见下文。此外,这里还有GitHub上的分支

https://github.com/michalmarczyk/clojure/tree/alien-hasheq-3

至于新的结果,性能损失相当大,我恐怕

`
;;; 使用补丁(murmur hashCode的默认版本)
(let [class-instance java.lang.String character-instance \a var-instance #'hash] (c/bench (clojure.lang.Util/hasheq class-instance)) (c/bench (clojure.lang.Util/hasheq character-instance)) (c/bench (clojure.lang.Util/hasheq var-instance)))
警告:最后的GC需要了1.409118084170768 %的计算时间
评估计数:655363680次,在60个样本中,样本容量为10922728次。

         Execution time mean : 96.459888 ns
Execution time std-deviation : 1.019817 ns

执行时间下四分位数:95.079086纳秒(2.5%)
执行时间上四分位数:98.684168纳秒(97.5%)

               Overhead used : 1.708347 ns

评估计数:675919140次,在60个样本中,样本容量为11265319次。

         Execution time mean : 88.965959 ns
Execution time std-deviation : 0.825226 ns

执行时间下四分位数:87.817159纳秒(2.5%)
执行时间上四分位数:90.755688纳秒(97.5%)

               Overhead used : 1.708347 ns

评估计数:574987680次,在60个样本中,样本容量为9583128次。

         Execution time mean : 103.881498 ns
Execution time std-deviation : 1.103615 ns

执行时间下四分位数:102.257474纳秒(2.5%)
执行时间上四分位数:106.071144纳秒(97.5%)

               Overhead used : 1.708347 ns

在60个样本中发现了1个异常值(1.6667%)

low-severe	 1 (1.6667 %)

异常值方差:1.6389 % 异常值略微增加了方差
nil

;;; 1.6.0
(let [class-instance java.lang.String character-instance \a var-instance #'hash] (c/bench (clojure.lang.Util/hasheq class-instance)) (c/bench (clojure.lang.Util/hasheq character-instance)) (c/bench (clojure.lang.Util/hasheq var-instance)))
警告:最后的GC需要了1.3353133083866688 %的计算时间
评估计数:1829305260次,在60个样本中,样本容量为30488421次。

         Execution time mean : 34.205701 ns
Execution time std-deviation : 0.379106 ns

执行时间下四分位数:33.680636纳秒(2.5%)
执行时间上四分位数:34.990138纳秒(97.5%)

               Overhead used : 1.718257 ns

在60个样本中发现了2个异常值(3.3333%)

low-severe	 1 (1.6667 %)
low-mild	 1 (1.6667 %)

异常值方差:1.6389 % 异常值略微增加了方差
评估计数:1858100340次,在60个样本中,样本容量为30968339次。

         Execution time mean : 30.401309 ns
Execution time std-deviation : 0.213878 ns

执行时间下四分位数:30.095976纳秒(2.5%)
执行时间上四分位数:30.871497纳秒(97.5%)

               Overhead used : 1.718257 ns

评估计数:1592932200次,在60个样本中,样本容量为26548870次。

         Execution time mean : 36.292934 ns
Execution time std-deviation : 0.333512 ns

执行时间下四分位数:35.795063纳秒(2.5%)
执行时间上四分位数:36.918183纳秒(97.5%)

               Overhead used : 1.718257 ns

在60个样本中发现了1个异常值(1.6667%)

low-severe	 1 (1.6667 %)

异常值方差:1.6389 % 异常值略微增加了方差
nil
`

使用新补丁(默认情况下没有额外的murmur步骤)的一个PHM和类/字符/变量结果

`
user=> (let [phm (apply hash-map (interleave (range 128) (range 128))) juhm (java.util.HashMap. phm)] #_(assert (= (hash phm) (hash juhm))) (c/bench (unchecked-add (clojure.lang.Util/hasheq phm) (unchecked-add (clojure.lang.Util/hasheq "foo") (clojure.lang.Util/hasheq 123)))))
警告:最后的GC需要了1.258952964663877 %的计算时间
评估计数:1007768460次,在60个样本中,样本容量为16796141次。

         Execution time mean : 58.195608 ns
Execution time std-deviation : 0.482804 ns

执行时间下四分位数:57.655857纳秒(2.5%)
执行时间上四分位数:59.154655纳秒(97.5%)

               Overhead used : 1.567532 ns

在60个样本中发现了1个异常值(1.6667%)

low-severe	 1 (1.6667 %)

异常值方差:1.6389 % 异常值略微增加了方差
nil
(let [class-instance java.lang.String character-instance \a var-instance #'hash] (c/bench (clojure.lang.Util/hasheq class-instance)) (c/bench (clojure.lang.Util/hasheq character-instance)) (c/bench (clojure.lang.Util/hasheq var-instance)))
评估计数:647944080次,在60个样本中,样本容量为10799068次。

         Execution time mean : 91.275863 ns
Execution time std-deviation : 0.659943 ns

执行时间下四分位数:90.330980纳秒(2.5%)
执行时间上四分位数:92.711120纳秒(97.5%)

               Overhead used : 1.567532 ns

评估计数:699506160次,在60个样本中,样本容量为11658436次。

         Execution time mean : 84.564131 ns
Execution time std-deviation : 0.517071 ns

执行时间下四分位数:83.765607纳秒(2.5%)
执行时间上四分位数:85.569206纳秒(97.5%)

               Overhead used : 1.567532 ns

在60个样本中发现了1个异常值(1.6667%)

low-severe	 1 (1.6667 %)

异常值方差:1.6389 % 异常值略微增加了方差
评估计数:594919980次,在60个样本中,样本容量为9915333次。

         Execution time mean : 100.336792 ns
Execution time std-deviation : 0.811312 ns

执行时间下四分位数:99.313490纳秒(2.5%)
执行时间上四分位数:102.167675纳秒(97.5%)

               Overhead used : 1.567532 ns

在60个样本中发现了3个异常值(5.0000%)

low-severe	 3 (5.0000 %)

异常值方差:1.6389 % 异常值略微增加了方差
nil
`

0

由 michalmarczyk 评论

这里有一个新的补丁(0001-CLJ-1372-consistent-hasheq-for-java.util.-List-Map-M-substring.patch),它采用了一种激进的策略,即用.class.getName().startsWith("java.util.")来替换Iterable/Map/Entry测试。 (我实验过.getClass().getPackage(),但性能极差。) 分支在这里

https://github.com/michalmarczyk/clojure/tree/alien-hasheq-4

这个补丁在"fall-through"情况下具有非常好的哈希性能

`
(let [class-instance java.lang.String character-instance \a var-instance #'hash] (c/bench (clojure.lang.Util/hasheq class-instance)) (c/bench (clojure.lang.Util/hasheq character-instance)) (c/bench (clojure.lang.Util/hasheq var-instance)))
警告:最终GC需要1.31690036780011 %的运行时间
评估次数:1661453640,在60个样本中的27690894次调用中。

         Execution time mean : 35.099750 ns
Execution time std-deviation : 0.422800 ns

执行时间下四分位数:34.454839 ns(2.5%)
执行时间上四分位数:35.953584 ns(97.5%)

               Overhead used : 1.556642 ns

评估次数:1630167600,在60个样本中的27169460次调用中。

         Execution time mean : 35.487409 ns
Execution time std-deviation : 0.309872 ns

执行时间下四分位数:35.083030 ns(2.5%)
执行时间上四分位数:36.190015 ns(97.5%)

               Overhead used : 1.556642 ns

发现了60个样本中的4个异常值(6.6667%)

low-severe	 3 (5.0000 %)
low-mild	 1 (1.6667 %)

异常值方差:1.6389 % 异常值略微增加了方差
评估次数:1440434700,在60个样本中的24007245次调用中。

         Execution time mean : 40.894457 ns
Execution time std-deviation : 0.529510 ns

执行时间下四分位数:40.055991 ns(2.5%)
执行时间上四分位数:41.990985 ns(97.5%)

               Overhead used : 1.556642 ns

nil
`

0
_评论由:michalmarczyk_发表

新的补丁(...-substring.patch)返回除List、Map、Map.Entry和Set之外,java.util.**类的hashCode,当然,那里没有行为改变。

以下是重复PHM查找(比1.6.0慢一些,但差距在1纳秒以内)和"添加三个hasheq"基准测试的基准数据(有补丁为66纳秒,无补丁为57纳秒)


user=> (let [phm (apply hash-map (interleave (range 128) (range 128))) juhm (java.util.HashMap. phm)] (assert (= (hash phm) (hash juhm))) (c/bench (clojure.lang.Util/hasheq phm)) (c/bench (clojure.lang.Util/hasheq juhm)))
评估次数:5183841240,在60个样本中的86397354次调用中。
执行时间平均值:10.076893 ns
执行时间标准差:0.182592 ns
执行时间下四分位数:9.838456 ns(2.5%)
执行时间上四分位数:10.481086 ns(97.5%)
额外开销:1.565749 ns
评估次数:3090420,在60个样本中的51507次调用中。
执行时间平均值:19.596627 µs
执行时间标准差:224.380257 ns
执行时间下四分位数:19.288347 µs(2.5%)
执行时间上四分位数:20.085620 µs(97.5%)
额外开销:1.565749 ns
nil

user=> (let [phm (apply hash-map (interleave (range 128) (range 128))) juhm (java.util.HashMap. phm)] #_(assert (= (hash phm) (hash juhm))) (c/bench (unchecked-add (clojure.lang.Util/hasheq phm) (unchecked-add (clojure.lang.Util/hasheq "foo") (clojure.lang.Util/hasheq 123)))))
警告:最终GC需要1.418253438197936 %的运行时间
评估次数:879210900,在60个样本中的14653515次调用中。
执行时间平均值:66.939309 ns
执行时间标准差:0.747984 ns
执行时间下四分位数:65.667310 ns(2.5%)
执行时间上四分位数:68.155046 ns(97.5%)
额外开销:1.724002 ns
nil


需要注意的是,我在评估1.6.0时,对于"三个hasheq"基准测试已获得无补丁的结果,所以应用补丁后的基准测试也是如此。处理许多不同类型的哈希会明显改变结果 -- 猜测是HotSpot在向hasheq传入几个不同类型后,退回了一些优化?
0

由 michalmarczyk 评论

这里有一个新的补丁(0005-CLJ-1372-consistent-hasheq-for-java.util.-List-Map-M.patch),该补丁引入了一个名为isAlien的静态方法,用于检查Map/Map.Entry/Iterable的instanceof,并使用此方法来测试“异类集合”。

初步基准测试结果很有前景

`
;;;“跌入”基准测试
(let [class-instance java.lang.String character-instance \a var-instance #'hash] (c/bench (clojure.lang.Util/hasheq class-instance)) (c/bench (clojure.lang.Util/hasheq character-instance)) (c/bench (clojure.lang.Util/hasheq var-instance)))
警告:最终GC所需时间占总运行时间的1.258979068087473%
评估计数:1598432100次,在26640535次调用的60个样本中。

         Execution time mean : 36.358882 ns
Execution time std-deviation : 0.566925 ns

执行时间下四分位数:35.718889纳秒(2.5%)
执行时间上四分位数:37.414722纳秒(97.5%)

               Overhead used : 1.823120 ns

在60个样本中发现了1个异常值(1.6667%)

low-severe	 1 (1.6667 %)

异常值方差:1.6389 % 异常值略微增加了方差
评估计数:1626362460次,在27106041次调用的60个样本中。

         Execution time mean : 35.426993 ns
Execution time std-deviation : 0.294517 ns

执行时间下四分位数:35.047064纳秒(2.5%)
执行时间上四分位数:36.058667纳秒(97.5%)

               Overhead used : 1.823120 ns

在60个样本中发现了1个异常值(1.6667%)

low-severe	 1 (1.6667 %)

异常值方差:1.6389 % 异常值略微增加了方差
评估计数:1461423180次,在24357053次调用的60个样本中。

         Execution time mean : 39.541873 ns
Execution time std-deviation : 0.423707 ns

执行时间下四分位数:38.943560纳秒(2.5%)
执行时间上四分位数:40.499433纳秒(97.5%)

               Overhead used : 1.823120 ns

在60个样本中发现了2个异常值(3.3333%)

low-severe	 2 (3.3333 %)

异常值方差:1.6389 % 异常值略微增加了方差
nil

;;;“三个hasheq”基准测试
user=> (let [phm (apply hash-map (interleave (range 128) (range 128))) juhm (java.util.HashMap. phm)] #_(assert (= (hash phm) (hash juhm))) (c/bench (unchecked-add (clojure.lang.Util/hasheq phm) (unchecked-add (clojure.lang.Util/hasheq "foo") (clojure.lang.Util/hasheq 123)))))
警告:最终GC所需时间占总运行时间的1.5536755331464491%
评估计数:820376460次,在13672941次调用的60个样本中。

         Execution time mean : 71.999365 ns
Execution time std-deviation : 0.746588 ns

执行时间下四分位数:70.869739纳秒(2.5%)
执行时间上四分位数:73.565908纳秒(97.5%)

               Overhead used : 1.738155 ns

在60个样本中发现了2个异常值(3.3333%)

low-severe	 2 (3.3333 %)

异常值方差:1.6389 % 异常值略微增加了方差
nil
`

0
_评论由:michalmarczyk_发表

啊,我漏掉了上述中重复的phm hasheq查找以及java.util.HashMap实例对的基准测试,这里提供这些测试以确保完整性(不过并不令人意外)


user=> (let [phm (apply hash-map (interleave (range 128) (range 128))) juhm (java.util.HashMap. phm)] (assert (= (hash phm) (hash juhm))) (c/bench (clojure.lang.Util/hasheq phm)) (c/bench (clojure.lang.Util/hasheq juhm)))
警告:最终GC所需时间占总运行时间的1.260853406580491%
评估计数:5369135760次,在89485596次调用的60个样本中。
              执行时间均值:10.380464纳秒
             标准差:3.407284纳秒
             执行时间下四分位数:9.510624纳秒(2.5%)
             执行时间上四分位数:11.461485纳秒(97.5%)
                   启动开销:1.566301纳秒

在60个样本中找到5个异常值(8.3333%)
    低严重      3(5.0000%)
    低轻微      2(3.3333%)
  异常值方差:96.4408%,方差严重被异常值放大
评估计数:3078180次,在51303次调用的60个样本中。
             执行时间均值:19.717981微秒
             标准差:209.896848纳秒
             执行时间下四分位数:19.401811微秒(2.5%)
             执行时间上四分位数:20.180163微秒(97.5%)
                   启动开销:1.566301纳秒

在60个样本中发现了2个异常值(3.3333%)
   低严重     2 (3.3333%)
 异常值方差:1.6389%。方差略受异常值影响
nil
0

由 alexmiller 评论

请不要提交任何更改哈希码除了使 Java 集合匹配 Clojure 集合的补丁 - 任何其他更改都不在本工单的范围之内。

一般来说,我现在更倾向于只看执行时间的平均值报告,而不是所有信息 - 全面准则输出的输出使得这些评论难以阅读和比较。

0

由 alexmiller 评论

请提供各种方法的总结,以及每个补丁相对于 1.6.0 的测试时间 - 比如为 Long、PHM、juHM、Class 以及“三个 hasheqs”测试提供哈希时间?

0
_由 richhickey 发表的评论:

“对多种不同类型的哈希会明显改变结果 - maybe HotSpot 在看到将多个不同类型传递给 hasheq 后会放弃一些优化?”

对 - 如果您的基准测试没有将此位设置为 megamorphic,您会得到各种扭曲的结果。
0
_评论由:michalmarczyk_发表

好的,我有一个我认为是改进的微基准测试:对于长、双、字符串、类、字符和 PHM(单个实例,因此它将是一个哈希查找)的 hasheqs 的异或。结果并不令人鼓舞。

单个形式,包括 {{require}} 以便方便运行;还提供了 {{j.u.HashMap}} (128个条目) hasheq 基准。


(do
  (require '[criterium.core :as c])
  (let [l    41235125123
        d    123.456
        s    "asdf;lkjh"
        k    BigInteger
        c    \S
        phm  (apply hash-map (interleave (range 128) (range 128)))
        juhm (java.util.HashMap. phm)
        f    (fn f []
               (-> (clojure.lang.Util/hasheq l)
                   (bit-xor (clojure.lang.Util/hasheq d))
                   (bit-xor (clojure.lang.Util/hasheq s))
                   (bit-xor (clojure.lang.Util/hasheq k))
                   (bit-xor (clojure.lang.Util/hasheq c))
                   (bit-xor (clojure.lang.Util/hasheq phm))))]
    (c/bench (f))
    (c/bench (hash juhm))))


由 Criterium 报告的平均执行时间

||版本||xor (ns)||j.u.HM (微秒)||
|未修复 1.6.0|148.128748|1.701640|
|0005 修复包|272.039667|21.201178|
|原始修复包|268.670316|21.169436|
|-替代修复包|271.747043|20.755397|

子串修复包损坏(见下文),所以我跳过了它。我描述为"原始"的修复包已作为0001-CLJ-1372-consistent-hasheq-for-java.util.-List-Map-M.patch附加。

所有修复包的共同决策

1. 在{{hasheq}}的默认返回上方多了一个额外的{{if}}语句,使用三向{{instanceof}}检查。

2. 测试的类型为{{j.u.Iterable}}、{{j.u.Map.Entry}}和{{j.u.Map}}。

3. {{Murmur3.hashOrdered}}接收{{Iterable}},因此它位于列表上。{{Map}}不扩展{{Iterable}},所以它单独列出。{{Map.Entry}}在列表上,因为最终哈希映射的方式是遍历并哈希它们的条目。

4. 实际的"异类" / 主类型哈希由一个独立的静态方法--{{clojure.lang.Util.doalienhasheq}}--完成,从理论上讲,这将允许{{hasheq}}更积极地内联,并将最坏的性能影响限制在异类集合上。

5. {{doalienhasheq}}检查{{Map}}、{{Map.Entry}}、{{Set}}和{{List}};条目转换为列表以进行哈希,映射通过条目集进行哈希,而列表和集合则直接传递给{{Murmur3}}。

6. 还有其他{{Iterable}}类型的默认情况--我们必须返回{{hashCode}}或将其与其他函数的组合结果{{hashCode}}返回,因为我们使用{{equals}}来测试这些以检查相等性。

0005修复包的{{hasheq}}调用一个单独的私有静态方法来执行三向类型检查,而其他修复包直接在实际的{{if}}测试中放置检查。替代修复包和0005修复包在默认情况下返回{{hashCode}},而原始修复包将{{Murmur3.hashInt}}与{{hashCode}}组合。

子串修复包仅适用于{{java.util.**}}类,因此没有解决问题(例如,它不会正确哈希Guava集合)。

所有修复包都改变了{{c.l.Util.hasheq}}并在{{clojure.lang.Util}}中添加了一个或两个新的静态方法,作为{{hasheq}}的辅助器。它们都没有改变其他任何东西。Murmuring hashCode是一个性能实验,它似乎对某些"快速情况"产生轻微的正影响(实际上,它是上面展示的微基准测试中当前三个修复包中表现最好的,尽管获胜的差距当然非常小)。因此,我认为所有当前的修复包实际上在范围上有限,仅限于与工单直接相关的更改;替代修复包和0005修复包肯定如此。
...