scala.concurrent.blocking - 它实际上做了什么?

时间:2015-03-16 00:50:04

标签: scala concurrency java.util.concurrent

我花了一段时间学习Scala执行上下文,底层线程模型和并发的主题。你能解释一下scala.concurrent.blocking "调整运行时行为的方式" "可以提高性能或避免死锁" scaladoc

中所述

the documentation中,它被表示为等待不实现Awaitable的api的手段。 (也许只是长时间运行的计算应该被包裹?)。

它实际上是做什么的?

Following through the source并不容易背叛其秘密。

1 个答案:

答案 0 :(得分:73)

blocking用于表示所包含的代码阻塞的ExecutionContext提示,并可能导致线程饥饿。这将使线程池有机会产生新线程以防止饥饿。这就是"调整运行时行为" 的含义。但它并不神奇,并且不会与每个ExecutionContext一起工作。

考虑这个例子:

import scala.concurrent._
val ec = scala.concurrent.ExecutionContext.Implicits.global

(0 to 100) foreach { n =>
    Future {
        println("starting Future: " + n)
        blocking { Thread.sleep(3000) }
        println("ending Future: " + n)
    }(ec)
}

这是使用默认的全局ExecutionContext。按原样运行代码,您会注意到100 Future都是立即执行的,但是如果删除blocking,它们一次只执行几个ExecutionContext。默认的Future将通过生成新线程来阻止调用(标记为这样),因此不会因运行import java.util.concurrent.Executors val executorService = Executors.newFixedThreadPool(4) val ec = ExecutionContext.fromExecutorService(executorService) (0 to 100) foreach { n => Future { println("starting Future: " + n) blocking { Thread.sleep(3000) } println("ending Future: " + n) }(ec) } 而过载。

现在看一下这个带有4个线程的固定池的示例:

ExecutionContext

这个blocking不是为了处理产生新线程而构建的,所以即使我的阻塞代码被Future包围,你也可以看到它仍然只能执行最多4 {{ 1}}一次。这就是为什么我们说"可以提高性能或避免死锁" - 它不能得到保证。正如我们在后者ExecutionContext中看到的那样,它根本得不到保证。

它是如何工作的?在链接时,blocking执行此代码:

BlockContext.current.blockOn(body)(scala.concurrent.AwaitPermission)

BlockContext.current从当前帖子中检索BlockContext,见hereBlockContext通常只是Thread混合了BlockContext特征。如源中所示,它存储在ThreadLocal中,或者如果它存储在BlockContext中。在那里找不到它,它是当前线程的模式匹配。如果当前线程不是DefaultBlockContext,则使用blockOn代替。

接下来,在当前BlockContext上调用blockOnBlockContextExecutionContext中的抽象方法,因此它的实现取决于BlockContext如何处理它。如果我们查看implementation for DefaultBlockContext(当前主题不是blockOn时),我们会发现blocking实际上什么也没做。因此,在非BlockContext中使用BlockContext意味着根本不会执行任何特殊操作,并且代码按原样运行,没有副作用。

global s的线程怎么样?例如,在blockOn上下文中,看到hereForkJoinPool做了更多。深入挖掘,您可以看到它在引擎盖下使用DefaultThreadFactory,同一代码段中定义的ForkJoinPool用于在blockOn中生成新线程。如果BlockContext(主题)没有ForkJoinPool的实施,则blocking不会知道您正在阻止,并且不会尝试生成更多主题作为回应。

Scala的Await也使用{{1}}进行实施。