在《2024Clojure状态调查》中分享您的想法!https://www.surveymonkey.com/r/clojure2024

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

0 投票
Collections

如果将暴露其 backing array 的(可变)Java 集合并发地传递到 c.c/sort,则多个线程将并发修改该集合。

`
user=> (def q (java.util.concurrent.ArrayBlockingQueue. 1))

'user/q

user=> (future (loop [] (.add q 1) (.remove q 1) (recur)))

object[clojure.core$future_call$reify__4393 0x4769b07b {:status :pending, :val nil}]

user=> (take 3 (distinct (repeatedly #(sort q))))
((1) () nil)
`

方法:将 coll 转换为一个序列,然后再转换为一个数组,从而保留原始集合。

补丁:0001-CLJ-1763-make-sort-thread-safe.patch

其他方法

  1. 在 sort 中记录,与 Java 数组类似,Java 以数组为后盾的集合将就地修改。
  2. 将 RT.toArray() 更改为 defensive copy 来自(非 IPersistentCollection)Java 集合返回的数组。由于该方法从多个路径调用,这有一些潜在的后果。
  3. 对于非 Clojure 集合,也可以使用 Collections.sort(),而不是将数组倒入数组并使用 Arrays.sort()。

6 答案

0 投票

评论者:alexmiller

帮助文档中写道:“如果 coll 是一个 Java 数组,它将进行修改。为了避免这种情况,对数组的副本进行排序。”这在当前情况下也是一条很好的建议。

将输入集合创建为一个序列会显著改变性能特征。

0 投票

评论者:alexmiller

我想说的是,我们不应该为了使任意 Java 集合更安全而牺牲持久集合的性能。但我们可能仍然在不影响持久集合性能和/或更新文档字符串的情况下使其更安全。

0 投票

评论者:bronsa

Alex,没有创建额外的序列,seq 调用已经存在

0 投票

评论者:alexmiller

嗯,这个说法有一定道理。之前的用法并没有强制整个 seq 的实现,只是第一个元素。也就是说,从快速测试来看,额外的开销在集合中似乎很小(由于它们的结构,vector seqs 实际上更快)。

0 投票

评论者:stu

我认为这应该是一个文档字符串的更改,如果需要进行任何更改的话。

0 投票
参考:https://clojure.atlassian.net/browse/CLJ-1763(由 bronsa 报告)
...