I cannot provide any link to documentation which will clearly state what will really happen, but we can conduct a simple experiment which will answer your question.
Just open the Scala REPL and paste the following code:
import java.util.concurrent.Executors
import scala.concurrent._
implicit val ec = new ExecutionContext {
val threadPool = Executors.newFixedThreadPool(1000);
def execute(runnable: Runnable) {
threadPool.submit(runnable)
println("execute!")
}
def reportFailure(t: Throwable) {}
}
future { 1 } map(_ + 1) filter (_ > 0) map (_ + 2)
It will print:
scala> future { 1 } map(_ + 1) filter (_ > 0) map (_ + 2)
execute!
execute!
execute!
execute!
res0: scala.concurrent.Future[Int] = scala.concurrent.impl.Promise$DefaultPromise@7ef3de76
So execute is called for every single operation you are doing (and as you can check in the documentation each function like map or filter takes ExecutionContext as an implicit parameter: http://www.scala-lang.org/api/2.10.6/#scala.concurrent.Future)
If you are looking for an alternative framework you should check scalaz Futures. I have no experience with them, but they seems to be what you are looking for. Check this thread: https://groups.google.com/forum/#!msg/scalaz/-PuakIf-g_4/7ydrU5VIfDQJ
Unlike the Future
implementation in scala 2.10, map
and flatMap
do NOT spawn new tasks and do not require an implicit ExecutionContext
. Instead, map
and flatMap
merely add to the current (trampolined) continuation that will be run by the 'current' thread, unless explicitly forked via Future.fork
or Future.apply
. This means that Future
achieves much better thread reuse than the 2.10 implementation and avoids needless thread pool submit cycles.
Future
also differs from the scala 2.10 Future
type in that it does not necessarily represent a running computation. Instead, we reintroduce nondeterminism explicitly using the functions of the scalaz.Nondeterminsm
interface. This simplifies our implementation and makes code easier to reason about, since the order of effects and the points of nondeterminism are made fully explicit and do not depend on Scala's evaluation order.
IMPORTANT NOTE: Future
does not include any error handling and should generally only be used as a building block by library writers who want to build on Future
's capabilities but wish to design their own error handling strategy. See scalaz.concurrent.Task
for a type that extends Future
with proper error handling -- it is merely a wrapper for Future[Either[Throwable,A]]
with a number of additional convenience functions.