scala中的并发map/foreach
我有一个迭代scala中的并发map/foreach,scala,concurrency,functional-programming,Scala,Concurrency,Functional Programming,我有一个迭代vals:Iterable[T]和一个没有任何相关副作用的长时间运行的函数:f:(T=>Unit)。现在,这以明显的方式应用于VAL: vals.foreach(f) 我希望对f的调用能够同时进行(在合理的范围内)。Scala基本库中是否有明显的函数?比如: Concurrent.foreach(8 /* Number of threads. */)(vals, f) 虽然f运行的时间相当长,但它足够短,我不希望每次调用都需要调用线程的开销,因此我正在寻找基于线程池的东西。我在sca
vals:Iterable[T]
和一个没有任何相关副作用的长时间运行的函数:f:(T=>Unit)
。现在,这以明显的方式应用于VAL
:
vals.foreach(f)
我希望对f
的调用能够同时进行(在合理的范围内)。Scala基本库中是否有明显的函数?比如:
Concurrent.foreach(8 /* Number of threads. */)(vals, f)
虽然
f
运行的时间相当长,但它足够短,我不希望每次调用都需要调用线程的开销,因此我正在寻找基于线程池的东西。我在scala 2.8中使用scala.actors.Futures时遇到了一些问题(我检查时发现有问题)。使用java LIB直接对我有效,不过:
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)
}
}
我会使用
scala.actors.Futures
:
vals.foreach(t => scala.actors.Futures.future(f(t)))
我喜欢未来的答案。然而,虽然它将并发执行,但它也将异步返回,这可能不是您想要的。正确的方法如下:
import scala.actors.Futures._
vals map { x => future { f(x) } } foreach { _() }
import scalaz.Scalaz._
import scalaz.concurrent.Strategy.Naive
具有parMap
。您将按如下方式使用它:
import scala.actors.Futures._
vals map { x => future { f(x) } } foreach { _() }
import scalaz.Scalaz._
import scalaz.concurrent.Strategy.Naive
这将为每个函子(包括Iterable
)配备parMap
方法,因此您只需执行以下操作:
vals.parMap(f)
您还可以获得parFlatMap
,parZipWith
,等等。的最新版本具有一些您可以使用的高阶并发功能
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)
请记住关闭池池您可以使用Scala标准库中的。
它们与普通集合一样,但它们的操作是并行运行的。在调用某些集合操作之前,只需执行par
调用
import scala.collection._
val array = new Array[String](10000)
for (i <- (0 until 10000).par) array(i) = i.toString
导入scala.collection_
val数组=新数组[字符串](10000)
对于(我2009年的许多答案仍然使用旧的scala.actors.Futures.\uz,它们不再在新的scala中。虽然Akka是首选方法,但更具可读性的方法是只使用并行(.par)集合:
vals.foreach{v=>f(v)}
变成
<代码> Val.P.Frace{{V=>F(V)} <代码> < /P>
或者,使用parMap可能会显得更简洁,但需要注意的是,您需要记住导入常用的Scalaz*。与往常一样,在Scala中有多种方法可以完成相同的事情!请注意,VAL
是一个严格的集合——如果它是惰性的(在Scala 2.7中,这包括范围
类)我想我们可以通过在map
和当前foreach
之间注入另一个foreach
调用来解决这个问题
那将是一个我们必须注入的映射,而不是另一个foreach?我也不清楚惰性集合的映射是否严格。最安全的方法可能是调用toArray。你是对的,foreach
显然是一个错误的东西,因为它返回Unit
。我的错!:-)惰性集合上的map
函数几乎总是非严格的,因此我们可以调用toList
(或toArray
),或者我们可以投影然后强制:(vals map{x=>future{f(x)}投影)。foreach{uuz()}
。我不知道这是否比简单的toList
好,但它肯定是不同的。当你说它“异步返回”是什么意思?这是否意味着它是非阻塞的?(为什么这会成为一个问题?)