Scala 的阻塞上下文似乎不能很好地处理混合阻塞/非阻塞作业。为什么?
Scala's blocking context doesn't seem to do well with mixed blocking / non-blocking jobs. Why?
我正在尝试理解 blocking
结构。虽然还不完全清楚它在内部是如何工作的,但我得到的一般想法是,只要我使用 Scala 的全局线程池,用 blocking
上下文包装我的代码将确保线程池会创建额外的 space 用于此作业(因为它不受 CPU 约束)。
(1 to 1000).foreach { i =>
Future {
println(i)
Thread.sleep(100 * 1000)
}
}
会很快显示只有8个作业可以同时运行,而
(1 to 1000).foreach { i =>
Future {
blocking {
println(i)
Thread.sleep(100 * 1000)
}
}
}
将显示现在我们有大约 250 个并发作业。哇!
然后让我措手不及的是
(1 to 1000).foreach { i =>
Future {
println(i)
Thread.sleep(100 * 1000)
}
}
('a' to 'z').foreach { c =>
Future {
blocking {
println(c)
Thread.sleep(100 * 1000)
}
}
}
将再次仅显示 8 个并发作业 -- 阻塞作业不会立即执行。
这是为什么? blocking
上下文的内部机制究竟是什么?
您的第一个循环启动了 8 个线程,并阻塞了,因为它需要再启动 992 个 futures 才能完成。
不确定 "caught you off guard" 具体是什么。一旦第一个 foreach
调用完成,它将继续进行第二个调用,然后再开始 26 个。
blocking
只有在您进入阻塞上下文后才会生效。由于您有 8 个非阻塞期货 运行,它不会启动任何新的期货,因此它们无法进入阻塞上下文。换句话说,Scala 不会 "know" 它们会阻塞,直到它们开始执行。
您可以认为第二个代码段是这样工作的:
- 第一个未来已创建并启动。
- 第一个 future 通过调用
blocking
发出阻塞信号,因此该实现为更多 future 腾出了空间。
- 同时,在主线程上,创建并启动了第二个未来。
- ...
而你的最后一个片段是这样的:
- 第一个未来已创建并开始。它并不表示它正在阻塞。
- 第二个未来也是如此。
- ...
- 第 9 个 future 已创建,但尚未启动,因为有 8 个非阻塞 future。
- ...
- 第 1001 个 future(第二个循环中的第一个)已创建,但尚未启动,因为有 8 个非阻塞 future。由于它没有启动,它永远没有机会通过调用
blocking
. 告诉实现它正在阻塞
我正在尝试理解 blocking
结构。虽然还不完全清楚它在内部是如何工作的,但我得到的一般想法是,只要我使用 Scala 的全局线程池,用 blocking
上下文包装我的代码将确保线程池会创建额外的 space 用于此作业(因为它不受 CPU 约束)。
(1 to 1000).foreach { i =>
Future {
println(i)
Thread.sleep(100 * 1000)
}
}
会很快显示只有8个作业可以同时运行,而
(1 to 1000).foreach { i =>
Future {
blocking {
println(i)
Thread.sleep(100 * 1000)
}
}
}
将显示现在我们有大约 250 个并发作业。哇! 然后让我措手不及的是
(1 to 1000).foreach { i =>
Future {
println(i)
Thread.sleep(100 * 1000)
}
}
('a' to 'z').foreach { c =>
Future {
blocking {
println(c)
Thread.sleep(100 * 1000)
}
}
}
将再次仅显示 8 个并发作业 -- 阻塞作业不会立即执行。
这是为什么? blocking
上下文的内部机制究竟是什么?
您的第一个循环启动了 8 个线程,并阻塞了,因为它需要再启动 992 个 futures 才能完成。
不确定 "caught you off guard" 具体是什么。一旦第一个 foreach
调用完成,它将继续进行第二个调用,然后再开始 26 个。
blocking
只有在您进入阻塞上下文后才会生效。由于您有 8 个非阻塞期货 运行,它不会启动任何新的期货,因此它们无法进入阻塞上下文。换句话说,Scala 不会 "know" 它们会阻塞,直到它们开始执行。
您可以认为第二个代码段是这样工作的:
- 第一个未来已创建并启动。
- 第一个 future 通过调用
blocking
发出阻塞信号,因此该实现为更多 future 腾出了空间。 - 同时,在主线程上,创建并启动了第二个未来。
- ...
而你的最后一个片段是这样的:
- 第一个未来已创建并开始。它并不表示它正在阻塞。
- 第二个未来也是如此。
- ...
- 第 9 个 future 已创建,但尚未启动,因为有 8 个非阻塞 future。
- ...
- 第 1001 个 future(第二个循环中的第一个)已创建,但尚未启动,因为有 8 个非阻塞 future。由于它没有启动,它永远没有机会通过调用
blocking
. 告诉实现它正在阻塞