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

欢迎!请查看 关于 页面了解有关此内容的更多信息。

0
集合

如果将一个(可变的)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() 改为从非 IPersistentCollection Java 集合中返回的数组进行防御性复制。这有几个潜在的后果,因为这个方法从几个路径中被调用。
  3. 对于非 Clojure 集合,也可以使用 Collections.sort() 而不是将它们倾倒为数组并使用 Arrays.sort()。

6 个答案

0

评论者:alexmiller

文档字符串说:“如果 coll 是 Java 数组,它将被修改。为了避免这种情况,对数组的副本进行排序。”这在本案中似乎也是一条很好的建议。

创建输入集合的序列视图将显着改变性能特征。

0

评论者:alexmiller

我猜我所说的意思是,我们不应该为了使任意的 Java 集合更加安全而牺牲持久集合的性能。但是,在没有影响持久集合性能以及/或者更新文档字符串的情况下,使它更加安全可能仍然是有用的。

0
通过

评论者:bronsa

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

0
通过

评论者:alexmiller

嗯,这在某种程度上是对的。之前的用法并没有强制实化整个 seq,只是第一个元素。换句话说,通过快速测试,额外的开销在集合上似乎很小(由于结构的原因,向量 seq 实际上更快)。

0
通过

评论者:stu

我认为这应该是文档字符串的更改,如果有什么变动的话。

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