scala中的并发map / foreach

时间:2009-11-17 21:31:31

标签: scala concurrency functional-programming

我有一个迭代vals: Iterable[T]和一个长期运行的函数,没有任何相关的副作用:f: (T => Unit)。现在,它以明显的方式应用于vals

vals.foreach(f)

我希望同时(在合理范围内)完成对f的调用。 Scala基础库中某处有明显的功能吗?类似的东西:

Concurrent.foreach(8 /* Number of threads. */)(vals, f)

虽然f合理地长时间运行,但它足够短,我不想为每个调用调用一个线程的开销,所以我正在寻找基于线程池的东西。

7 个答案:

答案 0 :(得分:16)

2009年的许多答案仍然使用旧的scala.actors.Futures._,它们不再是新的Scala。虽然Akka是首选方式,但更易读的方法是使用并行( .par )集合:

vals.foreach { v => f(v) }

变为

vals.par.foreach { v => f(v) }

或者,使用parMap可能看起来更简洁,但需要记住要记住导入通常的Scalaz *。像往常一样,在Scala中做同样事情的方法不止一种!

答案 1 :(得分:13)

ScalazparMap。您可以按如下方式使用它:

import scalaz.Scalaz._
import scalaz.concurrent.Strategy.Naive

这将为每个仿函数(包括Iterable)提供parMap方法,因此您可以这样做:

vals.parMap(f)

您还可以获得parFlatMapparZipWith

答案 2 :(得分:10)

我喜欢Futures答案。但是,虽然它将同时执行,但它也将异步返回,这可能不是你想要的。正确的方法如下:

import scala.actors.Futures._

vals map { x => future { f(x) } } foreach { _() }

答案 3 :(得分:3)

我在Scala 2.8中使用scala.actors.Futures时遇到了一些问题(当我检查时它出了问题)。但是,使用java libs直接为我工作:

final object Parallel {
  val cpus=java.lang.Runtime.getRuntime().availableProcessors
  import java.util.{Timer,TimerTask}
  def afterDelay(ms: Long)(op: =>Unit) = new Timer().schedule(new TimerTask {override def run = op},ms)
  def repeat(n: Int,f: Int=>Unit) = {
    import java.util.concurrent._
    val e=Executors.newCachedThreadPool //newFixedThreadPool(cpus+1)
    (0 until n).foreach(i=>e.execute(new Runnable {def run = f(i)}))
    e.shutdown
    e.awaitTermination(Math.MAX_LONG, TimeUnit.SECONDS)
  }
}

答案 4 :(得分:2)

我会使用scala.actors.Futures

vals.foreach(t => scala.actors.Futures.future(f(t)))

答案 5 :(得分:2)

最新版本的Functional Java具有一些您可以使用的高阶并发功能。

import fjs.F._
import fj.control.parallel.Strategy._
import fj.control.parallel.ParModule._
import java.util.concurrent.Executors._

val pool = newCachedThreadPool
val par = parModule(executorStrategy[Unit](pool))

然后......

par.parMap(vals, f)

请记住shutdown pool

答案 6 :(得分:0)

您可以使用Scala标准库中的Parallel Collections。 它们就像普通的收藏品一样,但它们的操作并行运行。您只需在调用某些集合操作之前进行par调用。

import scala.collection._

val array = new Array[String](10000)
for (i <- (0 until 10000).par) array(i) = i.toString