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

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

0
Collections

c.c/hash 总是使用 Java 集合的 hashCode,这与使用 Murmur3 的 Clojure 集合不兼容。

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

解决此问题的一种方法是在 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}中与=保持一致性。它还扩展了特殊处理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累加的基准测试。希望这是一个好的开始;毫无疑问,更多的基准测试将是有用的。

结果令人有些惊讶:在imy构建中,hasheq在PHM的基准测试中实际上比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 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

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.028614538339401 %的运行时间
评估次数:在17165805次调用中的60个样本,共1029948300次。
                 平均执行时间:56.797488 ns
    执行时间标准差:0.732221 ns
   执行时间下四分位数:55.856731 ns ( 2.5%)
   执行时间上四分位数:58.469940 ns (97.5%)
                   系统开销:1.836671 ns

在60个样本中发现1个异常值(1.6667%)
    低严重程度      1 (1.6667 %)
 来自异常的方差:1.6389% 方差略微被异常膨胀
nil

;; patch applied

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)))
评估次数:在92294978次调用中的60个样本,共5537698680次。
              平均执行时间:8.973200 ns
    执行时间标准差:0.157079 ns
   执行时间下四分位数:8.733544 ns ( 2.5%)
   执行时间上四分位数:9.289350 ns (97.5%)
                   系统开销:1.744772 ns
评估次数:在41360次调用中的60个样本,共2481600次。
              平均执行时间:24.287800 µs
    执行时间标准差:288.124326 ns
   执行时间下四分位数:23.856445 µs ( 2.5%)
   执行时间上四分位数:24.774097 µs (97.5%)
                   系统开销:1.744772 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.298136122909759 %的运行时间
评估次数:在15912525次调用中的60个样本,共954751500次。
              平均执行时间:61.681794 ns
    执行时间标准差:0.712110 ns
   执行时间下四分位数:60.622003 ns ( 2.5%)
   执行时间上四分位数:62.904801 ns (97.5%)
                   系统开销:1.744772 ns

在60个样本中发现1个异常值(1.6667%)
    低严重程度      1 (1.6667 %)
 来自异常的方差:1.6389% 方差略微被异常膨胀
nil


值得注意的是,其他分支提供的此补丁的早期版本没有为String单独创建分支。这使得实现IHashEq的对象的hasheq更快,但将“三哈希”基准测试的速度降低了大约2倍。
0

评论者:alexmiller

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

我对实现IHashEq的函数的成本并不特别关心,因为它们应该不受影响,除非存在可能的内联问题。我对指向所有检查的末端的hasheq对象的成本感到好奇。在注释高处的列表是一个很好的起点,例如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
`

新的补丁中单个PHM以及类/字符/变量结果(默认情况下无额外murmur步骤)

`
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),它采取了极端的方法,用类名上的.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)))
警告:最终垃圾收集器使用了1.31690036780011 %的运行时间
评估次数:1661453640,在27690894次调用的60个样本中。

         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

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

         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% 异常值可能导致方差略微膨胀
评估次数:1440434700,在24007245次调用的60个样本中。

         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)将java.util.**中的hashCode方法应用于除了List、Map、Map.Entry和Set之外的类,因此在这一方面没有行为改变。

以下是重复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,在86397354次调用的60个样本中。
              平均执行时间:10.076893纳秒
    标准偏差:0.182592纳秒
   执行时间下四分位数:9.838456纳秒(2.5%)
   执行时间上四分位数:10.481086纳秒(97.5%)
                  开销使用了1.565749纳秒
评估次数:3090420,在51507次调用的60个样本中。
             平均执行时间:19.596627微秒
    标准偏差:224.380257纳秒
   执行时间下四分位数:19.288347微秒(2.5%)
   执行时间上四分位数:20.085620微秒(97.5%)
                  开销使用了1.565749纳秒
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.418253438197936 %的运行时间
评估次数:879210900,在14653515次调用的60个样本中。
             平均执行时间:66.939309纳秒
    标准偏差:0.747984纳秒
   执行时间下四分位数:65.667310纳秒(2.5%)
   执行时间上四分位数:68.155046纳秒(97.5%)
                  开销使用了1.724002纳秒
nil


需要注意的是,我在对1.6.0进行基准测试时,在全新的JVM上获得了“三个hasheq”基准测试的无补丁结果,因此我使用补丁重新进行了基准测试。对许多不同类型的哈希可能会明显改变结果——也许HotSpot在看到几个不同类型传递给hasheq后,会退回到某些优化之后?
0
回答者:

评论者:michalmarczyk

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

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

`
;; “穿透”基准测试
(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个样本中,共有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个样本中,共有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个样本中,共有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”基准测试
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 %
评估次数:在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实例对的基准测试——现在这里有它们,为了完整性(不过没有惊喜)


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 %
评估次数:在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 % 异常值严重拉高了方差
评估次数:在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集合哈希码的补丁,除非是为了使Java集合与Clojure集合匹配 - 任何其他更改都不在本票据范围之内。

通常情况下,我更希望只看执行时间的平均值报告,而不是全部内容——完整的指标输出使得这些评论难以阅读和比较。

0

评论者:alexmiller

能否总结一下方法,并为每个补丁提供一个1.6.0与一致测试集的对比时间——比如Long、PHM、juHM、Class对hash时间的测试,以及“三个hasheq”测试的时间?

0
_由:richhickey_发表的评论

“对许多不同类型进行散列会明显改变结果——显然,HotSpot在看到传递给hasheq的几个不同类型后,会放弃一些优化?”

是的——如果你的基准测试没有将这个网站视为多态的,你将得到各种扭曲的结果。
0
_评论者:michalmarczyk_

好的,我想我找到了一个改进的微基准测试:对于一个long,一个double,一个字符串,一个class,一个字符和一个PHM(单个实例,因此将是一个hash查询)的hasheq的xor。结果不是很鼓舞人心。

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


(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 (µs)||
|未修改的 1.6.0|148.128748|1.701640|
|0005补丁|272.039667|21.201178|
|原始补丁|268.670316|21.169436|
|替代补丁|271.747043|20.755397|

子字符串补丁有缺陷(见下文),所以跳过了它。我描述为“原始”的那个补丁已附上,文件名为0001-CLJ-1372Consistenthasheqforjava.util.-ListMap.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}} 测试中直接进行了检查。-alternative 修补程序和 0005 修补程序在默认情况下返回 {{hashCode}},而原始修补程序则将 {{Murmur3.hashInt}} 与 {{hashCode}} 组合。

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

所有修补程序都修改了 {{c.l.Util.hasheq}} 并在 {{clojure.lang.Util}} 中添加了一个或两个新的静态方法,作为 {{hasheq}} 的辅助工具。它们都没有改变其他内容。Murmuring hashCode 是一个性能实验,它似乎对一些 "快速情况" 产生微小的积极影响(实际上,它是上述微基准测试中当前三个修补程序中表现最好的,尽管胜利的差距当然非常小)。因此,我认为所有当前修补程序实际上都是有限的,仅限于与票据直接相关的变化;-alternative 修补程序和 0005 修补程序当然是。
...