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

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

在文档中 ,它是作为一种手段来等待api不能实现的。 (也许只是长时间运行的计算应该被包装?)。

它到底是什么?

通过源头不容易背叛其秘密。

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而被重载。

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

 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) } 

这个ExecutionContext不是为处理产生新线程而构build的,所以即使我的阻塞代码被blocking包围了,也可以看到它每次最多只能执行4个Future 。 这就是为什么我们说它“可以提高性能或避免死锁” – 我们无法保证。 正如我们在后面的ExecutionContext所看到的那样,根本不能保证。

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

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

BlockContext.current从当前线程中获取BlockContext ,如下所示。 BlockContext通常只是一个带有BlockContext特性的Thread 。在源代码中可以看到,它存储在ThreadLocal ,或者如果在那里没有find它,它就会从当前线程中模式匹配。 如果当前线程不是BlockContext ,则使用DefaultBlockContext

接下来,在当前BlockContext上调用BlockContextblockOnblockOn中的抽象方法,所以它的实现取决于ExecutionContext如何处理它。 如果我们看一下DefaultBlockContext的实现 (当前线程不是BlockContext ),我们可以看到blockOn实际上什么都不做。 因此,在非BlockContext使用blocking意味着完全没有什么特别的,代码按原样运行,没有任何副作用。

什么是BlockContext的线程? 例如,在global范围内, blockOn可以看到更多。 深入挖掘,您可以看到它使用的是ForkJoinPool ,在同一个片段中定义的DefaultThreadFactory用于在ForkJoinPool产生新的线程。 如果没有从BlockContext (线程)执行blockOnForkJoinPool不知道你是否阻塞,并且不会尝试产生更多的线程作为响应。

斯卡拉的Await ,使用blocking其实施。