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...
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:
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.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With