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 添加一个特殊案例,就像它现在为 Strings 所做的那样。

有关此主题在 Clojure 群组中的讨论链接: https://groups.google.com/forum/#!topic/clojure/dQhdwZsyIEw

43 个答案

0

stu 发表的评论:

我认为这需要更多的考虑,并且不应该阻挡 1.6 版本。

0

stu 发表的评论:

截至 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累加结果。希望这是一个好的开始;我无疑认为还会需要额外的基准测试。

结果让我有些惊讶:PHM的hasheq在这项基准测试中我的构建中实际上比1.6.0快一点;"添加三个hasheq"基准测试在1.6.0上稍快。


;;; 1.6.0

;;; NB. 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)))
WARNING: 最后一次GC需要Runtime的1.24405836928592 %
Evaluation count : 5549560980 in 60 samples of 92492683 calls.
             Execution time mean : 9.229881 ns
    Execution time std-deviation : 0.156716 ns
   Execution time lower quantile : 8.985994 ns ( 2.5%)
   Execution time upper quantile : 9.574039 ns (97.5%)
                   Overhead used : 1.741068 ns

Found 2 outliers in 60 samples (3.3333 %)
    low-severe     2 (3.3333 %)
 Variance from outliers : 6.2652 % Variance is slightly inflated by outliers
Evaluation count : 35647680 in 60 samples of 594128 calls.
             Execution time mean : 1.695145 µs
    Execution time std-deviation : 20.186554 ns
   Execution time lower quantile : 1.670049 µs ( 2.5%)
   Execution time upper quantile : 1.740329 µs (97.5%)
                   Overhead used : 1.741068 ns

Found 2 outliers in 60 samples (3.3333 %)
    low-severe     2 (3.3333 %)
 Variance from outliers : 1.6389 % Variance is slightly inflated by outliers
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)))))
WARNING: 最后一次GC需要Runtime的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%)
 Variance from outliers : 1.6389 % Variance is slightly inflated by outliers
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)))
评估次数: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

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 %
评估次数:954751500 次在15912525次调用中的60个样本。
             平均执行时间:61.681794纳秒
    执行时间标准差:0.712110纳秒
   执行时间下四分位数:60.622003纳秒(2.5%)
   执行时间上四分位数:62.904801纳秒(97.5%)
                   占用开销:1.744772纳秒

在60个样本中发现了1个异常值(1.6667%)
    低严重程度     1(1.6667%)
 Variance from outliers : 1.6389 % Variance is slightly inflated by outliers
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)
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 %
评估计数: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
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 %
评估计数: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

Found 2 outliers in 60 samples (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步骤)的One PHM和Class/Character/Var结果

`
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
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)))
评估计数: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),它采用了极端的方法,将 Iterable/Map/Entry 测试替换为在类名上使用.startsWith("java.util.")。(我曾尝试使用.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,在 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)除了 List、Map、Map.Entry 和 Set 类之外,还为 java.util.** 类返回 hashCode,所以那里的行为没有改变。

以下是重复 PHM 查找(稍微慢于 1.6.0,但仍在 1 纳秒之内)和“新增三个哈希”基准的测试结果(有补丁时 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)))))
警告:最终的 GC 需要 1.418253438197936% 的运行时间
评估次数:879210900,在 14653515 次调用中的 60 个样本。
             平均执行时间:66.939309 纳秒
    标准差:0.747984 纳秒
   下四分位数执行时间:65.667310 纳秒(2.5%)
   上四分位数执行时间:68.155046 纳秒(97.5%)
                   开销:1.724002 纳秒
nil


需要注意的是,我在 1.6.0 性能测试时获得了新鲜 JVM 上的“三个哈希”基准的 no-patch 结果,因此我也以这种方式重复了对补丁的基准测试。处理多种不同类型会明显改变结果——假设 HotSpot 在将多个不同类型传递到 hasheq 后会从某些优化中退出?
0

评论由:michalmarczyk 提供

这里有一个新的补丁(0005-CLJ-1372-为java.util.-List-Map-M引入新的isAlien静态方法,用于检查instanceof 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 %的运行时间
评估次数:1598432100,在60个样本的26640535次调用中。

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

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

               Overhead used : 1.823120 ns

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

low-severe	 1 (1.6667 %)

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

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

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

               Overhead used : 1.823120 ns

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

low-severe	 1 (1.6667 %)

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

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

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

               Overhead used : 1.823120 ns

Found 2 outliers in 60 samples (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,在60个样本的13672941次调用中。

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

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

               Overhead used : 1.738155 ns

Found 2 outliers in 60 samples (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,在60个样本的89485596次调用中。
             平均执行时间:10.380464 ns
    执行时间标准偏差:3.407284 ns
   下四分位数执行时间:9.510624 ns (2.5%)
   上四分位数执行时间:11.461485 ns (97.5%)
                   开销使用:1.566301 ns

在60个样本中发现了5个异常值(8.3333%)
    低严重      3 (5.0000%)
    低轻微      2 (3.3333%)
  异常值方差:96.4408% 变差被异常值严重影响
评估次数:3078180,在60个样本的51303次调用中。
             平均执行时间:19.717981 µs
    执行时间标准偏差:209.896848 ns
   下四分位数执行时间:19.401811 µs (2.5%)
   上四分位数执行时间:20.180163 µs (97.5%)
                   开销使用:1.566301 ns

Found 2 outliers in 60 samples (3.3333 %)
    low-severe     2 (3.3333 %)
 Variance from outliers : 1.6389 % Variance is slightly inflated by outliers
nil
0

评论由:alexmiller 提供

请不要提交除使Java集合并入Clojure集合之外改变任何对象的hashCode的补丁 - 任何其他更改都不在本票据的范围之内。

一般来说,我目前更希望只看到执行时间的均值报告,而不是所有内容 - 详细的输出使得这些评论读写和比较都变得更加困难。

0

评论由:alexmiller 提供

能否提供一个关于方法概要的总结,以及针对一组固定测试用例的1.6.0版本与每个补丁的计时比较——比如 Long、PHM、juHM、Class 和 "三个hasheq" 测试的时间?

0
_由:richhickey_发表的评论

"对不同类型的哈希处理会导致结果产生明显变化——很可能是因为HotSpot在看到多个不同类型的hasheq输入后,放弃了某些优化?"

是的——如果你的基准测试没有将这个位作为多态处理,那么你将得到各种各样的扭曲结果。
0
_评论者:michalmarczyk_

有效,我认为这是对于这个问题的改进版微基准测试:一个长整型、一个双精度浮点型、一个字符串、一个类、一个字符和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 (µs)||
|未打补丁 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}} 测试中。-alternative 补丁和 0005 补丁在默认情况下返回 {{hashCode}},而原始补丁将 {{Murmur3.hashInt}} 与 {{hashCode}} 组合。

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

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