java - 为什么 Kotlin/Java 没有抢占式调度程序的选项?

标签 java multithreading kotlin jvm

繁重的 CPU 密集型任务可能会阻塞线程并延迟等待执行的其他任务。那是因为 JVM 不能中断正在运行的线程,需要程序员的帮助和手动中断。
所以在 Java/Kotlin 中编写 CPU 密集型任务需要人工干预才能使事情顺利运行,比如使用 Sequence在下面的代码中的 Kotlin 中。

fun simple(): Sequence<Int> = sequence { // sequence builder
    for (i in 1..3) {
        Thread.sleep(100) // pretend we are computing it
        yield(i) // yield next value
    }
}

fun main() {
    simple().forEach { value -> println(value) } 
}
据我了解,原因是拥有能够中断正在运行的线程的抢占式调度程序会产生性能开销。
但是有一个开关不是更好,所以你可以选择吗?如果您想使用更快的非抢占式调度程序运行 JVM。还是使用较慢的先发制人(在 N 条指令后中断和切换胎面)但能够平稳运行并且不需要人工来做到这一点?
我想知道为什么 Java/Kotlin 没有这样的 JVM 开关来允许选择你想要的模式。

最佳答案

当您使用 Kotlin 协程或 Java 虚拟线程(在 Loom 之后)进行编程时,您会从操作系统获得抢占式调度。
按照惯例,未阻塞的任务(即它们需要 CPU)在 Kotlin 默认调度程序或 Java ForkJoinPool 中的真实操作系统线程上多路复用。这些操作系统线程由操作系统抢先调度。
然而,与旧式多线程不同,任务在等待 I/O 时被阻塞时不会分配给线程。这在抢占方面没有区别,因为等待 I/O 的任务不可能抢占另一个正在运行的任务。
使用协程编程时,您不会得到同时对大量任务进行抢先式调度。如果您有许多需要 CPU 的任务,那么第一个 N 将分配给一个真正的线程,操作系统将对它们进行时间切片。其余的将在队列中等待,直到完成。
但在现实生活中,当您有 10000 个任务需要同时交互时,它们就是 I/O 绑定(bind)任务。平均而言,任何时候都没有太多需要 CPU 的线程,因此您从默认调度程序或 ForkJoinPool 获得的实际线程数是很多的。在正常操作中,等待线程的任务队列几乎总是空的。
如果您真的遇到需要同时交互 10000 个 CPU 密集型任务的情况,那么您无论如何都会感到难过,因为时间切片不会提供非常流畅的体验。

关于java - 为什么 Kotlin/Java 没有抢占式调度程序的选项?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63302512/

相关文章:

java - Java 的类似 Qt 的多值映射?

java - 将 XML 编译成 Java

java - 过滤器在 Glassfish 3.1.1 中不起作用

python - 在python中定期和异步地获取值

c# - 只锁定 1 个操作?

java - 从文件读取时跳过每 N 行

java - 同步计数器大小()

android - 是否可以从任何地方通过语音命令触发您的应用程序?

kotlin - 为什么 Kotlin 需要在编译后捆绑其运行时?

android - 初始化接口(interface)数组时转换为lambda