您可以使用 Scala 并行集合。它们目前是 Scala nightly 版本的一部分,并将在 Scala 2.9 中发布。这个想法是,常规集合中可用的大多数操作都是并行的,因此可以以相同的方式使用并行集合。
目前,有几种可用的集合类型 - 并行范围、并行数组和并行哈希尝试。例如,您可以调用并行map
and fold
对并行数组的操作如下:
scala> val pa = (0 until 10000).toArray.par
pa: scala.collection.parallel.mutable.ParArray[Int] = ParArray(0, 1, 2, 3, 4, 5, 6,...
scala> pa.map(_ + 1)
res0: scala.collection.parallel.mutable.ParArray[Int] = ParArray(1, 2, 3, 4, 5, 6, 7,...
scala> pa map { v => if (v % 2 == 0) v else -v }
res1: scala.collection.parallel.mutable.ParArray[Int] = ParArray(0, -1, 2, -3, 4, -5,...
scala> pa.fold(0) { _ + _ }
res2: Int = 49995000
还有其他可用的并行收集操作。注意fold
必须采用结合运算符 - 在上面的示例中,加法是结合的 ((A + B) + C == A + (B + C)),即您可以按任何顺序添加数字的子序列,并且您将始终获得相同的结果总和(reduce
有类似的合同)。
另一件需要注意的事情是传递给并行集合的闭包是同时调用的。如果它们有副作用,例如修改环境中的局部变量,则必须同步这些访问。例如,你可以这样做:
scala> var a = 0
a: Int = 0
scala> pa foreach { a += _ }
scala> a
res1: Int = 49995000
scala> a = 0
a: Int = 0
scala> pa foreach { a += _ }
scala> a
res7: Int = 49990086
并且每次都有不同的结果,因为foreach
调用{ a += _ }
在平行下。在上面的例子中,a
应该同步,用锁或原子保护。
但其想法是使用内置组合器来完成任务并倾向于函数式编程,避免如上例所示的局部副作用。
您可能想在其他答案中提供的链接中详细了解其内部机制。