I am trying to understand Scala futures coming from Java background: I understand you can write:
val f = Future { ... }
then I have two questions:
Furthermore, how can I achieve a scheduledFuture
, the one that executes after a specific time delay? Thanks
Scala concurrency is built on top of the Java concurrency model. On Sun JVMs, with a IO-heavy workload, we can run tens of thousands of threads on a single machine. A Thread takes a Runnable. You have to call start on a Thread in order for it to run the Runnable.
Future represents a result of an asynchronous computation that may or may not be available yet. When we create a new Future, Scala spawns a new thread and executes its code. Once the execution is finished, the result of the computation (value or exception) will be assigned to the Future.
NOTE: With Future. onComplete() we are no longer blocking for the result from the Future but instead we will receive a callback for either a Success or a Failure.
Promise is an object which can be completed with a value or failed with an exception. A promise should always eventually be completed, whether for success or failure, in order to avoid unintended resource retention for any associated Futures' callbacks or transformations. Source Promise.scala. AnyRef, Any.
The Future { ... }
block is syntactic sugar for a call to Future.apply
(as I'm sure you know Maciej), passing in the block of code as the first argument.
Looking at the docs for this method, you can see that it takes an implicit ExecutionContext
- and it is this context which determines how it will be executed. Thus to answer your second question, the future will be executed by whichever ExecutionContext is in the implicit scope (and of course if this is ambiguous, it's a compile-time error).
In many case this will be the one from import ExecutionContext.Implicits.global
, which can be tweaked by system properties but by default uses a ThreadPoolExecutor
with one thread per processor core.
The scheduling however is a different matter. For some use-cases you could provide your own ExecutionContext
which always applied the same delay before execution. But if you want the delay to be controllable from the call site, then of course you can't use Future.apply
as there are no parameters to communicate how this should be scheduled. I would suggest submitting tasks directly to a scheduled executor in this case.
Andrzej's answer already covers most of the ground in your question. Worth mention is that Scala's "default" implicit execution context (import scala.concurrent.ExecutionContext.Implicits._
) is literally a java.util.concurrent.Executor
, and the whole ExecutionContext concept is a very thin wrapper, but is closely aligned with Java's executor framework.
For achieving something similar to scheduled futures, as Mauricio points out, you will have to use promises, and any third party scheduling mechanism.
Not having a common mechanism for this built into Scala 2.10 futures is a pity, but nothing fatal.
A promise is a handle for an asynchronous computation. You create one (assuming ExecutionContext
in scope) by calling val p = Promise[Int]()
. We just promised an integer.
Clients can grab a future that depends on the promise being fulfilled, simply by calling p.future
, which is just a Scala future.
Fulfilling a promise is simply a matter of calling p.successful(3)
, at which point the future will complete.
Play 2.x solves scheduling by using promises and a plain old Java 1.4 Timer.
Here is a linkrot-proof link to the source.
Let's also take a look at the source here:
object Promise {
private val timer = new java.util.Timer()
def timeout[A](message: => A, duration: Long, unit: TimeUnit = TimeUnit.MILLISECONDS)
(implicit ec: ExecutionContext): Future[A] = {
val p = Promise[A]()
timer.schedule(new java.util.TimerTask {
def run() {
p.completeWith(Future(message)(ec))
}
}, unit.toMillis(duration))
p.future
}
}
This can then be used like so:
val future3 = Promise.timeout(3, 10000) // will complete after 10 seconds
Notice this is much nicer than plugging a Thread.sleep(10000)
into your code, which will block your thread and force a context switch.
Also worth noticing in this example is the val p = Promise...
at the function's beginning, and the p.future
at the end. This is a common pattern when working with promises. Take it to mean that this function makes some promise to the client, and kicks off an asynchronous computation in order to fulfill it.
Take a look here for more information about Scala promises. Notice they use a lowercase future
method from the concurrent
package object instead of Future.apply
. The former simply delegates to the latter. Personally, I prefer the lowercase future
.
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