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

欢迎!请参阅关于页面以了解更多关于如何使用本站的信息。

0
集合

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}的=操作保持一致。此外,它将字符串的特殊处理扩展到所有未处理的类型(有关此内容的评论见下文)。

也可在此处获得

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)))
警告:最后需要1.24405836928592 %的运行时间来完成GC
评估计数: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)))))
警告:最后一次垃圾回收需要运行时周期的1.028614538339401 %
评估次数:1029948300次,在17165805次调用中的60个样本。
             执行时间平均值: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)))
评估次数:5537698680次,在92294978次调用中的60个样本。
             执行时间平均值:8.973200纳秒
    执行时间标准差:0.157079纳秒
   执行时间下四分位数:8.733544纳秒(2.5%)
   执行时间上四分位数:9.289350纳秒(97.5%)
                   使用开销:1.744772纳秒
评估次数:2481600次,在41360次调用中的60个样本。
             执行时间平均值: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)))))
警告:最后一次垃圾回收需要运行时周期的1.298136122909759 %
评估次数:954751500次,在15912525次调用中的60个样本。
             执行时间平均值: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更快,但将“三个哈希”基准测试慢了大约1倍。
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的默认版本)
(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和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 %
评估次数: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),它采用了极端的方法,用类名前缀.startsWith("java.util.")来替换Iterable/Map/Entry的测试。(我尝试过getClass().getPackage(),但性能非常差。)分支在这里

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

使用此补丁“穿透”案例的哈希性能似乎非常好

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

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

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

               Overhead used : 1.556642 ns

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

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

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

               Overhead used : 1.556642 ns

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

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

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

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

执行时间下四分位数:40.055991纳秒(2.5%)
执行时间上四分位数:41.990985纳秒(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纳秒以内)以及“添加三个hasheqs”基准测试(有补丁为66纳秒,无补丁为57纳秒)


用户=> (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个86397354次调用样本中为5183841240次。
             执行时间平均值:10.076893纳秒
    执行时间标准差:0.182592纳秒
   执行时间下四分位数:9.838456纳秒(2.5%)
   执行时间上四分位数:10.481086纳秒(97.5%)
                   使用开销:1.565749纳秒
Evaluation count : 3090420 in 60 samples of 51507 calls.
             Execution time mean : 19.596627 µs
    Execution time std-deviation : 224.380257 ns
   Execution time lower quantile : 19.288347 µs ( 2.5%)
   Execution time upper quantile : 20.085620 µs (97.5%)
                   使用开销:1.565749纳秒
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%的运行时间
Evaluation count : 879210900 in 60 samples of 14653515 calls.
             Execution time mean : 66.939309 ns
    Execution time std-deviation : 0.747984 ns
   Execution time lower quantile : 65.667310 ns ( 2.5%)
   Execution time upper quantile : 68.155046 ns (97.5%)
                   Overhead used : 1.724002 ns
nil


值得注意的是,我在测试1.6.0时,在一个全新的JVM上获得了“三个hasheqs”基准测试的无补丁结果,所以我也是用这个结果来重复应用补丁后的基准测试的。对多种不同类型进行哈希会明显改变结果——难道HotSpot在看到传递给hasheq的不同类型数量较多后会放弃某些优化吗?
0

评论者:michalmarczyk

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

初步基准测试结果很有希望

`
;;; “跌落”基准测试
(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)))
警告:最终垃圾回收需要运行时1.258979068087473%的时间
评估次数:在26640535次调用中的60个样本中为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 % 异常值略微增加了标准差
评估次数:在27106041次调用中的60个样本中为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 % 异常值略微增加了标准差
评估次数:在24357053次调用中的60个样本中为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)))))
警告:最终垃圾回收需要运行时1.5536755331464491%的时间
评估次数:在13672941次调用中的60个样本中为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)))
警告:最终垃圾回收需要运行时1.260853406580491%的时间
评估次数:在89485596次调用中的60个样本中为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% 异常值严重影响了方差
评估次数:在51303次调用中的60个样本中为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集合之外的hashCode的补丁——任何其他更改都不在本票据的范围内。

总的来说,我此刻更希望只报告平均执行时间,而不是所有内容——完整的criterium输出使得这些注释难以阅读和比较。

0

评论者:alexmiller

能否总结一下方法,并给出1.6.0与每个补丁一致的测试集的时间——比如Long、PHM、juHM、Class和“三个hasheqs”测试的时间?

0
_评论由:richhickey_ 撰写

“对不同类型的哈希进行运算会导致结果明显变化——大概HotSpot在看到向hasheq传入多个不同类型后,退出了某些优化?”

是的——如果你的基准测试没有将这一点视为多态型,你将得到各种各样的扭曲结果。
0
_由 michalmarczyk 评论

好吧,我认为这个微基准有所改进:对Long、double、字符串、类、字符和PHM(单实例,因此将是哈希查找)的hasheqs进行异或。结果并不令人鼓舞。

包含{{require}}的单个形式,以便方便运行;还包括一个{{j.u.HashMap}}(128项)hasheq基准


(do
  (require '[criterium.core :as c]))
  (let [l 41235125123]
     d 123.456
     s "asdf;lkjh"
     k BigInt
     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. 对“alien”(外来)或“host”类型的实际散列操作由一个独立的静态方法执行--`{{clojure.lang.Util.doalienhasheq}}`--其原理是这将允许更激进地对`hasheq`进行内联,并将性能损失限制在外部集合中。

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

6. 对于其他{{Iterable}}类型也存在默认情况--我们必须返回{{hashCode}}或将这些类型与其他函数结合使用{{hashCode}}的结果,因为我们使用{{equals}}来测试它们的等价性。

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

子字符串补丁仅适用于{{java.util.**}}类,因此无法解决这个问题(例如,它不能正确散列Guava集合)。

所有补丁都改变了{{c.l.Util.hasheq}}并在{{clojure.lang.Util}}中添加一个或两个新的静态方法,作为{{hasheq}}的辅助工具。没有它们之间的任何改变。Murmur散列hashCode是一个性能实验,似乎是某些“快速情况”的轻微正面影响(实际上,它仍然是上述微基准测试中当前三个补丁中表现最好的,尽管胜利的差距当然非常小)。因此,我认为所有当前补丁实际上仅限于直接与票据相关的变化;替代补丁和0005补丁肯定是这样的。
...