我们最近在我的操作系统课上讨论了很多线程,我想到了一个问题。
由于 Go(和 Java)使用用户空间线程而不是内核线程,这是否意味着您不能有效地利用多个内核,因为操作系统只将 CPU 时间分配给进程而不是线程本身?
我们最近在我的操作系统课上讨论了很多线程,我想到了一个问题。
由于 Go(和 Java)使用用户空间线程而不是内核线程,这是否意味着您不能有效地利用多个内核,因为操作系统只将 CPU 时间分配给进程而不是线程本身?
是什么让您认为 Go 使用用户空间线程?
它没有。它使用操作系统线程并且可以利用多个内核。
您可能对默认情况下 Go 仅使用 1 个线程来运行您的程序这一事实感到困惑。如果您启动两个goroutine,它们会在一个线程中运行。但是,如果一个 goroutine 阻塞了 I/O,Go 创建第二个线程并继续在新线程上运行另一个 goroutine。
如果您真的想解锁完整的多核功能,只需使用该GOMAXPROCS()
功能即可。
runtime.GOMAXPROCS(4); //somewhere in main
现在您的程序将使用 4 个操作系统线程(而不是 1 个),并且能够完全使用例如 4 核系统。
最新版本的 Java 使用 OS 线程,尽管不一定与 Java 线程进行一对一的映射。Java 显然在许多硬件线程上都可以很好地工作。
我认为“用户空间线程”是指(例如)Go 的 goroutines。
确实,使用 goroutine 进行并发的效率低于设计(通过手工和科学计算)将工作单元分配给 OS 线程的专用算法。
但是:每个 Go 程序都位于一个环境中,旨在解决特定问题。对于环境向 Go 程序发出的每个请求,都可以启动一个新的 goroutine。如果环境正在向 Go 程序发出并发请求,则使用 goroutine 的 Go 程序可能比串行程序运行得更快,即使 Go 程序仅使用 1 个 OS 线程也是如此。goroutine 能够以更快的速度处理请求(即使只使用 1 个 OS 线程)的原因是,当与 A 关联的环境部分暂时无法切换时,Go 程序会自动从 goroutine A 切换到 goroutine B回应。
但是,是的,使用 goroutine 并自动将它们分配给多个 OS 线程确实比设计(通过手工和科学计算)将工作单元分配给 OS 线程的专用算法效率低。