2024 年 Clojure 调查问卷! 中分享您的想法。

欢迎!请参阅 关于 页面获取更多有关此功能的信息。

+1 投票
Clojure
已关闭

'zipmap 构建一个没有 transients 的映射,而使用 transients 可能会提高性能。

方法: 在内部使用 transient 映射,同时使用迭代器对键和值进行操作。持久映射的返回方式保持不变。定义也相应地移动,以便位于 #'transient 下方。

性能

(def xs (range 16384))
(def ys (range 16))

| 表达式 | 1.7.0-beta3 | +patch | |
| :-- | :-- | :-- | :-- | :-- |
| (zipmap xs xs) | 4.50 毫秒 | 2.12 毫秒 | 大映射
| (zipmap ys ys) | 2.75 微秒 | 2.07 微秒 | 小映射

补丁: CLJ-1005-zipmap-iterators.patch

由以下人员筛选: Alex Miller

关闭时的注释: 已在 1.10.2-rc1 中修复

13 个答案

0 投票

评论者:aaron

为什么保留旧的实现并在旁边加注释?如果我们打算迁移到新的实现,则应该删除旧实现。

0 投票

评论者:michalmarczyk

如工单说明中所述,之前附带的补丁遵循了 into 的模式,其非 transients 启用的定义仍然保留在 core.clj 中,并在前面加上了 #_ — 我不确定这是否在所有情况下都期望的。

以下是移除了旧实现的新补丁。

0 投票

评论者:jafingerhut

感谢更新补丁,米哈伊尔。很抱歉提出这样一个小问题,但您是否介意使用另一个名字来命名更新后的补丁?我知道JIRA可以处理同名多个附件,但我的预筛选代码还没有那么发达,这可能会导致讨论补丁时的混淆。

0 投票

评论者:michalmarczyk

谢谢提醒,安迪!我已重新上传名为新名称的补丁。

0 投票

评论者:jafingerhut

在米哈伊尔的更新补丁添加后,假设性地将“审批”从“不完整”改回“无”,以解决此票据标记为不完整的原因。

0 投票

评论者:aaron

这个补丁看起来不错,应用起来也很流畅。我们需要配合哪些额外的测试来验证这个补丁是否能提供预期的改进。另外,是否有关于这个票据开始的讨论?这里的信息不多。

0 投票

评论者:michalmarczyk

嗨,亚伦,

感谢您调查此事!

根据我能观察到的,这个改动极大地提升了{{zipmap}}大地图的性能。对于小地图,有轻微的改善。以下是两个基本的Criterium基准测试({{transient-zipmap}}在REPL中定义为补丁那样)

`
;; 大地图
user=> (def xs (range 16384))

'user/xs

user=> (last xs)
16383
user=> (c/bench (zipmap xs xs))
评估次数:13920次,在60个样本中调用232次。

         Execution time mean : 4.329635 ms
Execution time std-deviation : 77.791989 us

执行时间下四分位数:4.215050毫秒(2.5%)
执行时间上四分位数:4.494120毫秒(97.5%)
nil
user=> (c/bench (transient-zipmap xs xs))
评估次数:21180次,在60个样本中调用353次。

         Execution time mean : 2.818339 ms
Execution time std-deviation : 110.751493 us

执行时间下四分位数:2.618971毫秒(2.5%)
执行时间上四分位数:3.025812毫秒(97.5%)

样本60个中有2个异常值(3.3333%)

low-severe	 2 (3.3333 %)

异常值的方差:25.4675%,由于异常值的增大而适度膨胀方差
nil

;; 小地图
user=> (def ys (range 16))

'user/ys

user=> (last ys)
15
user=> (c/bench (zipmap ys ys))
评估次数: 16639020,在277317次调用中的60个样本。

         Execution time mean : 3.803683 us
Execution time std-deviation : 88.431220 ns

执行时间下四分位数: 3.638146微秒(2.5%)
执行时间上四分位数: 3.935160微秒(97.5%)
nil
user=> (c/bench (transient-zipmap ys ys))
评估次数: 18536880,在308948次调用中的60个样本。

         Execution time mean : 3.412992 us
Execution time std-deviation : 81.338284 ns

执行时间下四分位数: 3.303888微秒(2.5%)
执行时间上四分位数: 3.545549微秒(97.5%)
nil
`

显然,只要transient满足它们的契约,语义就得到了保留。

我想我可能没有为这个任务启动一个ggroup线程,抱歉。

0 投票

评论者:jafingerhut

2012年8月15日的补丁0001-Use-transient-map-in-zipmap.2.patch在2014年9月3日对Clojure进行了一些提交后,无法干净地应用于最新的master。

我还没有检查该补丁是否容易更新。请参阅http://dev.clojure.org/display/community/Developing Patches中的“更新陈旧补丁”部分以获取有关如何更新补丁的建议。

0 投票
_评论者: michalmarczyk_

谢谢,Andy。更新很简单——自动rebase。这是更新的补丁。
0 投票

评论者: gshayban

使用clojure.lang.RT/iter的新补丁,criterium在最佳情况下表现提升了>30%。可能分配更少,但我没有测量。CLJ-1499(更好的迭代器)相关

0 投票

评论者: justinspedding

4年后,这个在core命名空间中的zipmap实现仍然没有使用transient map。为何从未应用这个?

0 投票
_评论者: alexmiller_

这里提出了多种方法,但尚未确定共识方法。需要一些时间来集中精力于此,但目前还不是优先事项。
0 投票
参考: https://clojure.atlassian.net/browse/CLJ-1005(由michalmarczyk报告)
...