Scala 中的阻塞关键字
blocking keyword in Scala
Future(blocking(blockingCall()))
和 blocking(Future(blockingCall()))
有什么区别?这两个都在 scala.concurrent._
中定义
我看过 at the scala docs and some other stack overflow answers,但仍不清楚两者之间的区别。
blocking
提示 ExecutionContext
它包含阻塞代码,因此它可能会产生一个新线程以防止死锁。这假定 ExecutionContext
可以做到这一点,但并非所有都可以做到。
让我们逐一看看。
Future(blocking(blockingCall()))
这需要隐式 ExecutionContext
来执行 Future
。如果正在使用的 ExecutionContext
是 BlockContext
(就像 scala.concurrent.ExecutionContext.Implicits.global
一样),它可能能够在其线程池中生成一个新线程来处理阻塞调用,如果需要的话。如果不是,则不会发生任何特殊情况。
blocking(Future(blockingCall()))
这告诉我们Future(blockingCall())
可能是一个阻塞调用,所以和上面一样处理。除了这里,Future.apply
是非阻塞的,所以使用 blocking
有效地除了增加一点开销之外什么也做不了。 ExecutionContext
我们从这里调用它并不重要,因为它无论如何都不会阻塞。 但是, 中的阻塞调用 Future
将阻塞 ExecutionContext
中的线程 运行 , without 提示其阻塞。所以,没有理由这样做。
我在 中更深入地解释了 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)) }
Future(blocking(blockingCall()))
和 blocking(Future(blockingCall()))
有什么区别?这两个都在 scala.concurrent._
我看过 at the scala docs and some other stack overflow answers,但仍不清楚两者之间的区别。
blocking
提示 ExecutionContext
它包含阻塞代码,因此它可能会产生一个新线程以防止死锁。这假定 ExecutionContext
可以做到这一点,但并非所有都可以做到。
让我们逐一看看。
Future(blocking(blockingCall()))
这需要隐式 ExecutionContext
来执行 Future
。如果正在使用的 ExecutionContext
是 BlockContext
(就像 scala.concurrent.ExecutionContext.Implicits.global
一样),它可能能够在其线程池中生成一个新线程来处理阻塞调用,如果需要的话。如果不是,则不会发生任何特殊情况。
blocking(Future(blockingCall()))
这告诉我们Future(blockingCall())
可能是一个阻塞调用,所以和上面一样处理。除了这里,Future.apply
是非阻塞的,所以使用 blocking
有效地除了增加一点开销之外什么也做不了。 ExecutionContext
我们从这里调用它并不重要,因为它无论如何都不会阻塞。 但是, 中的阻塞调用 Future
将阻塞 ExecutionContext
中的线程 运行 , without 提示其阻塞。所以,没有理由这样做。
我在 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)) }