Reputation: 15351
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
Upvotes: 13
Views: 1931
Reputation: 1830
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
.
Upvotes: 3
Reputation: 103837
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.
Upvotes: 11