这个scala并行数组代码线程安全吗?

时间:2011-05-07 11:51:00

标签: scala parallel-collections

我想将并行数组用于任务,在开始编码之前,我有兴趣知道这个小snipept是否是线程安全的:

import collection.mutable._

var listBuffer = ListBuffer[String]("one","two","three","four","five","six","seven","eight","nine")
var jSyncList  = java.util.Collections.synchronizedList(new java.util.ArrayList[String]())
listBuffer.par.foreach { e =>
    println("processed :"+e)
    // using sleep here to simulate a random delay
    Thread.sleep((scala.math.random * 1000).toLong)
    jSyncList.add(e)
}
jSyncList.toArray.foreach(println)

是否有更好的方法来处理具有并行集合的内容,并在其他地方累积结果?

5 个答案:

答案 0 :(得分:5)

您发布的代码非常安全;我不确定前提:为什么你需要在非并行的集合中累积并行集合的结果?并行集合的一个重点是它们看起来像其他集合。

我认为并行集合还将提供seq方法来切换到顺序集合。所以你应该使用它!

答案 1 :(得分:3)

为了使这种模式安全:

listBuffer.par.foreach { e => f(e) }

f必须能够以安全的方式同时运行。我认为安全多线程所需的规则相同(访问共享状态需要是线程安全的,f调用不同e的顺序不是确定性的,您可以当您开始在f)中同步语句时遇到死锁。

此外,我不清楚并行集合为您提供了在处理时修改的底层集合的保证,因此可添加/删除元素的可变列表缓冲区可能是一个糟糕的选择。你永远不知道下一个编码器什么时候会在foo(listBuffer)之前调用类似foreach的内容,并将该引用传递给另一个可能在处理时改变列表的线程。

除此之外,我认为对于需要很长时间的任何f,可以同时调用,并且e可以不按顺序处理,这是一个很好的模式。

immutCol.par.foreach { e => threadSafeOutOfOrderProcessingOf(e) }

免责声明:我自己没有尝试过@colls,但是我很期待有问题/答案向我们展示什么效果很好。

答案 2 :(得分:2)

synchronisedList应该是安全的,虽然println可能会产生意想不到的结果 - 您无法保证打印项目的顺序,甚至您的打印件不会在中间交错字符。

同步列表也不太可能是你能做到这一点的最快方法,更安全的解决方案是map对不可变集合(Vector可能是你最好的选择),然后打印全部之后的行(按顺序):

val input = Vector("one","two","three","four","five","six","seven","eight","nine")
val output  = input.par.map { e =>
  val msg = "processed :" + e
  // using sleep here to simulate a random delay
  Thread.sleep((math.random * 1000).toLong)
  msg
}
println(output mkString "\n")

您还会注意到此代码与您的示例具有尽可能多的实用性:)

答案 3 :(得分:2)

这段代码很奇怪 - 为什么要将东西并行添加到需要同步的东西?你会增加争用并获得绝对没有回报。

事物的原则 - 通过并行处理积累结果,使用foldreduceaggregate等内容可以更好地实现。

答案 4 :(得分:2)

您发布的代码是安全的 - 由于数组列表的状态不一致而不会出现错误,因为对它的访问是同步的。

但是,并行集合同时(同时)处理项目,并且无序处理。乱序意味着可以在2.元素之前处理54.元素 - 您的同步数组列表将包含非预定义顺序的项目。

一般来说,最好使用mapfilter和其他功能组合器将集合转换为另一个集合 - 这将确保如果集合中有一些集合(如{{{{{{{ 1}} s)。例如:

Seq

始终返回ParArray(1, 2, 3, 4).map(_ + 1)

但是,如果您需要将特定的线程安全集合类型(例如ParArray(2, 3, 4, 5)或同步集合)传递给某些API中的某个方法,则从并行foreach中修改它是安全的。

最后,笔记 - 并行集合提供对数据的并行批量操作。可变并行集合在某种意义上不是线程安全的,您可以从不同的线程向它们添加元素。像插入地图或附加缓冲区这样的可变操作仍然需要同步。