我有一个迭代vals: Iterable[T]
和一个长期运行的函数,没有任何相关的副作用:f: (T => Unit)
。现在,它以明显的方式应用于vals
:
vals.foreach(f)
我希望同时(在合理范围内)完成对f
的调用。 Scala基础库中某处有明显的功能吗?类似的东西:
Concurrent.foreach(8 /* Number of threads. */)(vals, f)
虽然f
合理地长时间运行,但它足够短,我不想为每个调用调用一个线程的开销,所以我正在寻找基于线程池的东西。
答案 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)
Scalaz有parMap
。您可以按如下方式使用它:
import scalaz.Scalaz._
import scalaz.concurrent.Strategy.Naive
这将为每个仿函数(包括Iterable
)提供parMap
方法,因此您可以这样做:
vals.parMap(f)
您还可以获得parFlatMap
,parZipWith
等
答案 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