alexandru / scala-best-practices

A collection of Scala best practices
4.39k stars 623 forks source link

Rule 4.4 example #17

Open ramn opened 10 years ago

ramn commented 10 years ago

I think the example can be simplified to this:

import java.util.concurrent.Executors
import scala.concurrent.{Await, Future, ExecutionContext}
import scala.concurrent.duration._

implicit val ec = ExecutionContext.fromExecutor(Executors.newFixedThreadPool(1))
Await.result(Future(Await.result(Future("foo"), Duration.Inf)), Duration.Inf)

Which will wait forever, but if the thread pool is increased to 2 threads it will return "foo" immediately.

It is not necessary to spawn several futures from inside a future (addOne() twice). It is awaiting (blocking) on a future inside another future that causes the lock (exhausts the pool). This isn't as clear as it could be in the example.

Usage of blocking in this situation will not help however since it is a fixed thread pool, for which there is no remedy.

alexandru commented 10 years ago

Yeah, the example can be simplified.

However I find that the usage of blocking is still valuable as it serves documenting purposes.

Plus usually the thread-pool is injected from somewhere, being a bad idea to hard-code it and so it's often a matter of configuration ... change the thread-pool, then it starts working again. Which is why operations that block are error prone, as their correctness depends on the configuration of the underlying thread-pool. Hence clearly seeing in code things that block is very important.

BTW, Await.result already uses blocking in its implementation. But then you can also see it clearly that it blocks. So an example using Await.result is not the most fortunate. But couldn't think of anything better.