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

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

0
Collections

c.c/hash 总是使用 Java 集合的 hashCode,当与使用 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 添加一个特殊案例,就像现在为 Strings 做的那样。

有关此主题的 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 日之前的提交中是可以干净应用的,唯一的问题似乎是一个更改了 diff 上下行的差异。鉴于有关是否希望进行此类更改的讨论,似乎在决定是否进行更改之前需要更多思考。

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}的=操作一致。此外,它将字符串的特殊处理扩展到其他未处理的类型(有关说明,请参阅下文)。

它也可以在这里找到

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

更早的版本在这里

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

如果我的理解正确,需要基准测试的主要是给定的Clojure类型上clojure.lang.Util/hasheq的“分发时间”。因此,我反复对同样的持久哈希映射进行散列,这基于这种衡量仅测量IHashEq实例上的分发时间。然后我进行了另一个基准测试,散列PHM、字符串和长值,并使用unchecked-add添加这些结果。希望这是一个好的开始;我确信更多的基准测试将会是很有用的。

对我来说,结果有些出乎意料:在这个基准测试中,PHM上的hasheq在我的构建中实际上比1.6.0快;在1.6.0上,“三个hasheq添加”的基准测试稍快。


;;; 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 ns
    执行时间标准差:0.156716 ns
   执行时间下四分位数:8.985994 ns(2.5%)
   执行时间上四分位数:9.574039 ns(97.5%)
                   中断使用:1.741068 ns

在60个样本中发现了2个异常值(3.3333%)
    2(3.3333%)低严重
 异常值方差:6.2652 %。方差被异常值轻微膨胀
评估计数:35647680在60个样本中的594128次调用。
             执行时间平均值:1.695145 µs
   执行时间标准差:20.186554 ns
   执行时间下四分位数:1.670049 µs(2.5%)
   执行时间上四分位数:1.740329 µs(97.5%)
                   中断使用:1.741068 ns

在60个样本中发现了2个异常值(3.3333%)
    2(3.3333%)低严重
 异常值方差:1.6389 %。方差被异常值轻微膨胀
nil

用户=> (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.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

;; 补丁应用

用户=> (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

用户=> (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.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


顺便提一下,其他分支上可用的该补丁的早期版本没有为String单独开一个分支。这使得实现IHashEq的对象的hasheq更快,但将“三次hash”基准测试速度降低了大约2倍。
0

评论者:alexmiller

为了清楚起见,请按名称参考此处附上的补丁,以便随着时间的推移,我们不需要将附件时间与评论时间相关联。

我并不特别担心实现IHashEq的事物的成本,因为它们除了可能存在的内联问题外,应该不受影响。我对hasheq对通过case结尾并支付所有检查成本的对象的成本感到好奇。上面注释中的列表是一个不错的选择,例如Class、Character和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默认版本)
user=> (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 %的运行时间
评估计数:在60个样本的10922728次调用中为655363680。

         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

评估计数:在60个样本的11265319次调用中为675919140。

         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

评估计数:在60个样本的9583128次调用中为574987680。

         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
user=> (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 %的运行时间
评估计数:在60个样本的30488421次调用中为1829305260。

         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 % 异常值略微增加了方差
评估计数:在60个样本的30968339次调用中为1858100340。

         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

评估计数:在60个样本的26548870次调用中为1592932200。

         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和Class/Character/Var结果

`
用户=> (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 %的运行时间
评估计数:在60个样本的16796141次调用中为1007768460。

         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
user=> (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)))
评估计数:在60个样本的10799068次调用中为647944080。

         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

评估计数:在60个样本的11658436次调用中为699506160。

         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 % 异常值略微增加了方差
评估计数:在60个样本的9915333次调用中为594919980。

         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),它采用了一种极端的方法,用.className.startsWith("java.util.")替换了Iterable/Map/Entry测试。(我尝试过.getClass().getPackage(),但性能糟糕。)分支在这里

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

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

`
user=> (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)返回java.util.**非List,Map,Map.Entry和Set类的hashCode,当然,这里没有行为变化。

以下是重复PHM查找(略慢于1.6.0,不过1 ns以内)和"添加三个hasheq"基准测试的基准


用户=> (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

用户=> (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实例,并使用该方法来测试“外星集合”。

初步基准测试结果令人鼓舞

`
;;; “直接跳入”基准测试
user=> (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 %的运行时时间
评估计数:在60个样本中的26640535次调用中为1598432100。

         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 % 异常值略微增加了方差
评估计数:在60个样本中的27106041次调用中为1626362460。

         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 % 异常值略微增加了方差
评估计数:在60个样本中的24357053次调用中为1461423180。

         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”基准测试
用户=> (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 %的运行时时间
评估计数:在60个样本中的13672941次调用中为820376460。

         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实例对的基准测试——这里是为了完整性(没有惊喜)


用户=> (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 %的运行时时间
评估计数:在60个样本中的89485596次调用中为5369135760。
             执行时间均值: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% 剔除值严重拉高了方差
评估计数:在60个样本中的51303次调用中为3078180。
             执行时间均值: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

能否提供一些方法的总结,以及一组一致测试对每个补丁的所需时间 - 比如Long、PHM、juHM、Class和“三个hasheqs”测试的哈希值的时间?

0
评论由:richhickey_ 发表

"对多种不同类型的哈希处理会显著改变结果 - 据推测,HotSpot在看到几个不同类型传递给hasheq后,会从某些优化中退回?"

是的 - 如果你的基准测试不将这个站点视为多态形,你将得到各种扭曲的结果。
0
_由michalmarczyk发表的评论_

好的,我认为这是对该问题的改进微基准测试:对long、double、字符串、类、字符和PHM(单个实例,所以它将是一个哈希查找)的hasheq进行异或。结果并不令人鼓舞。

包括{{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. 在默认返回上方额外一个{{if}}语句,用于在{{hasheq}}中进行三方{{instanceof}}检查。

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

3. {{Murmur3.hashOrdered}} 接受 {{Iterable}},所以它出现在列表上。{{Map}} 不扩展 {{Iterable}},所以被单独列出。{{Map.Entry}} 在列表上,因为在最终的计算映射哈希值的方式是遍历和哈希它们的条目。

4. "alien" 或 "host" 类型的实际哈希是由一个单独的静态方法 -- {{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 补丁当然是这样。
...