在Scala中阻止关键字

时间:2015-06-24 15:03:07

标签: scala concurrency io future

Future(blocking(blockingCall()))blocking(Future(blockingCall()))之间的区别是什么?这两个都在scala.concurrent._

中定义

我看过at the scala docs和其他一些stack overflow answers,但仍然不清楚其区别。

1 个答案:

答案 0 :(得分:22)

blocking充当ExecutionContext它包含阻塞代码的提示,以便它可以生成一个新线程以防止死锁。这假设ExecutionContext可以做到这一点,但不是全部都可以做到。

让我们逐一看一下。

Future(blocking(blockingCall()))

这需要隐式ExecutionContext来执行Future。如果正在使用的ExecutionContextBlockContext(如scala.concurrent.ExecutionContext.Implicits.global是),则可能能够在其线程池中生成新线程以处理阻塞调用(如果需要)。如果它不是,那么没有什么特别的事情发生。

blocking(Future(blockingCall()))

这告诉我们Future(blockingCall())可能是阻止调用,因此它的处理方式与上面相同。除此之外,Future.apply是非阻塞的,因此有效使用blocking只会增加一点开销。我们从这里调用它ExecutionContext并不重要,因为它无论如何都不会阻塞。 但是,<{em> Future内的阻止调用将阻止ExecutionContext中正在运行的线程,没有< / em>暗示其阻止。所以,没有理由这样做。

我在this answer中更深入地解释了blocking

REPL示例:

import java.util.concurrent.Executors
import scala.concurrent._
val ec = scala.concurrent.ExecutionContext.Implicits.global
val executorService = Executors.newFixedThreadPool(4)
val ec2 = ExecutionContext.fromExecutorService(executorService)

def blockingCall(i: Int): Unit = { Thread.sleep(1000); println("blocking call.. " + i) }

// Spawns enough new threads in `ec` to handle the 100 blocking calls
(0 to 100) foreach { i => Future(blocking(blockingCall(i)))(ec) }

// Does not spawn new threads, and `ec2` reaches thread starvation
// execution will be staggered as threads are freed
(0 to 100) foreach { i => Future(blocking(blockingCall(i)))(ec2) }

// `blocking` does nothing because the `Future` is executed in a different context,
// and `ec2` reaches thread starvation
(0 to 100) foreach { i => blocking(Future(blockingCall(i))(ec2)) }

// `blocking` still does nothing, but `ec` does not know to spawn new threads (even though it could)
// so we reach thread starvation again
(0 to 100) foreach { i => blocking(Future(blockingCall(i))(ec)) }