Scala - ExecutorService应该用于在线程之间拆分工作吗?

时间:2013-04-23 19:14:36

标签: scala concurrency

来自Java背景,在多个线程之间拆分多个任务的问题可以很容易地使用ExecutorService并通过该接口提交任务。你会说同样的方法在Scala世界中有意义吗?如果是这样,是否有该API的Scala版本?

如果不是,您会推荐什么方法?演员似乎有点矫枉过正,因为我认为它们主要用于线程通信......

3 个答案:

答案 0 :(得分:3)

纯粹的Scala方式

Scala的并发模型基于Erlang actor模型。这是一种略有不同的方法。要充分利用Scala的并发性,请使用类似Akka的东西。基本的使用思路非常简单。

最简单的任务是使用Future(异步操作)。阅读有关此HERE的更多信息。 Executors框架不是您应该采用的方法。有很多选项可以实现强大的多线程| Scala应用程序中的并行性:

  1. Akka
  2. Lift演员(使用Lift Web框架时)。
  3. Finagle(Twitter RPC框架)。
  4. Scala 2.10中的默认Scala actor库,DEPRECATED。阅读更多HERE
  5. Scala / Java互操作性方法

    Actors可能会对您用于实现并发的方式进行重大改变,而Java在那里没有缺点。因此,您仍然可以在Scala应用程序中使用Executor框架进行多线程处理。

    这意味着您几乎完全依赖于本机Java并发结构,但它会让您不得不进行更改。在Scala HERE中阅读有关如何执行此操作的详细信息。

答案 1 :(得分:3)

如果您不想参加演员路线,那么您当然可以使用ExecutionContextFutures。如果你在范围内有一个隐含的ExecutionContext,如果你有一组你希望同时运行的固定任务,你可以做这样的事情:

val f1 = Future{
  //do something here
}  
val f2 = Future{
  //do something else here
} 
val aggFut = for{
  f1Val <- f1
  f2Val <- f2
} yield (f1Val, f2Val)

aggFut onComplete{
  case Success(tup) => //handle success case here
  case Failure(ex) => //handle failure here
}

在这个例子中,Success中的tup将按顺序包含f1和f2的结果。

如果要运行动态数量的并行任务,可以执行以下操作:

val futs = someList.map(item => Future{...})
val aggFut = Future.sequence(futs)
aggFut onComplete{
  case Success(list) => //handle success case here
  case Failure(ex) => //handle failure here
}    

在这个成功案例中,Success将包含从Future函数返回的任何类型的List。

最后,如果你想执行一些基于序列的异步任务,你可以这样做:

val fut = for{
  val1 <- Future{...}
  val2 <- Future{...}
} yield val2
fut onComplete{
  case Success(v2) => //handle success case here
  case Failure(ex) => //handle failure here
} 

在这种情况下,val1值可用于计算Future的{​​{1}}。这只是表面上的问题。如果您有兴趣了解更多信息,请查看http://docs.scala-lang.org/overviews/core/futures.html

答案 2 :(得分:1)

这是parallel collections的一个很好的用例(如果任务比较繁重):

val TasksNumber = 27
val tasks = List.fill(TasksNumber) { () => Thread.sleep(10000) }
tasks.par.map(t => t.apply)