Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scala - should ExecutorService be used for splitting work among the threads?

Coming from a Java background, a problem of splitting multiple tasks amongst multiple threads can be easily using ExecutorService and submitting tasks through that interface. Would you say the same approach makes sense in Scala world? If so, is there a Scala version of that API?

If no, what approach would you recommend? Actors seem to be a bit of an overkill, as I would envision them to be used for thread communication mostly...

like image 511
Bober02 Avatar asked Mar 25 '23 05:03

Bober02


2 Answers

The pure Scala way

Scala's concurrency model is based around the Erlang actor model. It's a slightly different approach. To fully exploit Scala's concurrency, use something like Akka. The basic usage idea is fairly simple.

The most simple task is using a Future(an asynchronous action). Read more about this HERE. The Executors framework is not the approach you should take. There are quite a few options to achieve powerful multi-threaded| parallelisms in your Scala applications:

  1. Akka
  2. Lift actors(when using the Lift web framework).
  3. Finagle(The Twitter RPC framework).
  4. The default Scala actors library, DEPRECATED in Scala 2.10. Read more HERE.

The Scala/Java interoperability approach

Actors may be a drastic change to the way you are used to implementing concurrency, and Java doesn't have shortcomings there. So you can still use the Executor framework for multi-threading in Scala applications.

It means you will rely almost entirely on native Java concurrency structures, but it gets you there with having to change much. Read more on how to do that in Scala HERE.

like image 175
flavian Avatar answered Apr 14 '23 15:04

flavian


If you don't want to go the actor route, then you can certainly make due with an ExecutionContext and Futures. Provided you had an implicit ExecutionContext in scope, you could do something like this if you had a fixed set of tasks that you wanted to run concurrently:

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
}

In this example, the tup in the Success would contain the result of f1 and f2 in that order.

If you had a dynamic number of parallel tasks to run, you could do something like this:

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
}    

In this success case, the Success would wrap a List of whatever type is returned from the Future function.

Lastly, if you wanted to perform some sequence based set of async tasks, you could do something like this:

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

In this case, the value val1 would be available to the Future that is calculating val2. This is only really scratching the surface. If you are interested in learning more, you should check out http://docs.scala-lang.org/overviews/core/futures.html

like image 20
cmbaxter Avatar answered Apr 14 '23 14:04

cmbaxter