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
上调用BlockContext
。 blockOn
是blockOn
中的抽象方法,所以它的实现取决于ExecutionContext
如何处理它。 如果我们看一下DefaultBlockContext
的实现 (当前线程不是BlockContext
),我们可以看到blockOn
实际上什么都不做。 因此,在非BlockContext
使用blocking
意味着完全没有什么特别的,代码按原样运行,没有任何副作用。
什么是BlockContext
的线程? 例如,在global
范围内, blockOn
可以看到更多。 深入挖掘,您可以看到它使用的是ForkJoinPool
,在同一个片段中定义的DefaultThreadFactory
用于在ForkJoinPool
产生新的线程。 如果没有从BlockContext
(线程)执行blockOn
, ForkJoinPool
不知道你是否阻塞,并且不会尝试产生更多的线程作为响应。
斯卡拉的Await
,使用blocking
其实施。