Future and ExecutionContext
A Future[A] is a value of type A that will exist later. Writing Future { work } hands work to a thread pool and returns immediately, so the current thread can keep going. The thread pool is chosen by an ExecutionContext — a given (implicit) value every Future method asks for. For examples and small programs, import scala.concurrent.ExecutionContext.Implicits.global supplies the standard one: a pool with roughly one thread per CPU core.
import scala.concurrent.{Future, Await}
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration.*
def slowSquare(n: Int): Int =
Thread.sleep(200)
n * n
@main def run(): Unit =
val f: Future[Int] = Future(slowSquare(7))
println("future started, main keeps going")
println(s"done yet? ${f.isCompleted}")
val result = Await.result(f, 2.seconds)
println(s"result: $result")
println(s"done yet? ${f.isCompleted}")
println(f.value)future started, main keeps going
done yet? false
result: 49
done yet? true
Some(Success(49))Future(slowSquare(7)) returned at once; the square was computed on a pool thread while main printed. Await.result blocks until the value arrives or the timeout expires. f.value is an Option[Try[Int]]: None while running, then Some(Success(...)) or Some(Failure(...)).
Start two Futures, slowSquare(3) and slowSquare(4), then await both and print their sum.
Await.result parks a whole thread doing nothing. In a real service you never call it in the middle of your code: you return the Future and let the web framework or main wait once, at the very edge. Every example on this page ends with one Await because that is the simplest way to get a deterministic printed result.Cannot find an implicit ExecutionContext
import scala.concurrent.{Future, Await}
import scala.concurrent.duration.*
@main def run(): Unit =
val f = Future(21 * 2)
println(Await.result(f, 2.seconds))-- [E172] Type Error: Main.scala:5:24
5 | val f = Future(21 * 2)
| ^
|Cannot find an implicit ExecutionContext. You might add
|an (implicit ec: ExecutionContext) parameter to your method.
|
|The ExecutionContext is used to configure how and on which
|thread pools asynchronous tasks (such as Futures) will run,
|so the specific ExecutionContext that is selected is important.
|
|If your application does not define an ExecutionContext elsewhere,
|consider using Scala's global ExecutionContext by defining
|the following:
|
|implicit val ec: scala.concurrent.ExecutionContext = scala.concurrent.ExecutionContext.global
|
|The following import might fix the problem:
|
| import scala.concurrent.ExecutionContext.Implicits.global
|
1 error found
Compilation failedFuture.apply has a using parameter of type ExecutionContext — it needs to know which thread pool should run the block. Nothing in scope provides one, so the compiler stops. map, flatMap, recover and onComplete ask for one too.
In a small program, import the global pool. In a library or service, take it as a parameter ((using ec: ExecutionContext)) so the caller decides which pool runs your work.
import scala.concurrent.{Future, Await}
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration.*
@main def run(): Unit =
val f = Future(21 * 2)
println(Await.result(f, 2.seconds))TimeoutException from Await.result
import scala.concurrent.{Future, Await}
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration.*
@main def run(): Unit =
val slow = Future { Thread.sleep(2000); "done" }
println(Await.result(slow, 500.millis))Exception in thread "main" java.util.concurrent.TimeoutException: Future timed out after [500 milliseconds]
at scala.concurrent.Future$.timeoutError(Future.scala:612)
at scala.concurrent.impl.Promise$DefaultPromise.tryAwait0(Promise.scala:272)
at scala.concurrent.impl.Promise$DefaultPromise.result(Promise.scala:285)
at scala.concurrent.Await$.result$$anonfun$1(package.scala:216)
at scala.concurrent.BlockContext$DefaultBlockContext$.blockOn(BlockContext.scala:67)
at scala.concurrent.Await$.result(package.scala:133)
at Main$package$.run(Main.scala:7)
at run.main(Main.scala:5)The work takes two seconds but the caller only agreed to wait half a second. Await.result gives up and throws TimeoutException on the waiting thread. The Future itself is not cancelled — it keeps running in the background; Scala Futures have no cancel button.
Pick a timeout that matches what the work really needs, or decide what the caller should see when the work is too slow. For a real deadline on a request, handle the timeout as a value instead of letting it crash main.
import scala.concurrent.{Future, Await}
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.duration.*
import scala.util.Try
@main def run(): Unit =
val slow = Future { Thread.sleep(2000); "done" }
val answer = Try(Await.result(slow, 500.millis)).getOrElse("still working, try later")
println(answer)