34

Go 的多线程方法与其他方法(例如 pthread、boost::thread 或 Java 线程)有什么区别?

4

4 回答 4

27

引用自第 3 天教程<- 阅读此内容以获取更多信息。

Goroutines 根据需要被多路复用到系统线程上。当一个 goroutine 执行阻塞系统调用时,没有其他 goroutine 被阻塞。

我们会在某个时候对 CPU 绑定的 goroutine 做同样的事情,但是现在,如果你想要用户级并行,你必须设置 $GOMAXPROCS。或调用 runtime.GOMAXPROCS(n)。

一个 goroutine 不一定对应一个 OS 线程。它可以具有较小的初始堆栈大小,并且堆栈将根据需要增长。

需要时,可以将多个 gorouitine 多路复用到单个线程中。

更重要的是,这个概念如上所述,goroutine 是一个顺序程序,它可能会阻塞自己但不会阻塞其他 goroutine。

Goroutines 在 gccgo 中被实现为 pthreads,因此它也可以与 OS 线程相同。它将操作系统线程的概念与我们在编程时对多线程的思考分开。

于 2009-11-16T02:08:36.570 回答
13

IMO,Go 中的多线程吸引人的是通信设施:与 pthread 不同,pthread 必须构建通信基础设施(互斥体、队列等),在 Go 中,它默认以一种方便的形式提供。

简而言之,由于良好的通信设施(如果我可以这么说,类似于 Erlang),使用线程有“低摩擦” 。

于 2009-11-16T01:44:18.240 回答
12

在参考编译器 (5g/6g/8g) 中,主调度程序 ( src/pkg/runtime/proc.c ) 创建 N 个 OS 线程,其中 N 由 runtime.GOMAXPROCS(n) 控制(默认为 1)。每个调度程序线程从主列表中拉出一个新的 goroutine 并开始运行它。goroutine(s) 将继续运行,直到进行系统调用(例如 printf)或对通道进行操作,此时调度程序将获取下一个 goroutine 并从它停止的点运行它(参见gosched() 在src/pkg/runtime/chan.c中调用)。

出于所有意图和目的,调度是使用协程实现的。可以使用 setjmp() 和 longjmp() 直接用 C 语言编写相同的功能,Go(以及其他实现轻量级/绿色线程的语言)只是为您自动执行该过程。

轻量级线程的好处是因为它都是用户空间,创建一个“线程”非常便宜(分配一个小的默认堆栈)并且由于线程如何相互通信的固有结构而可以非常有效。缺点是它们不是真正的线程,这意味着单个轻量级线程可以阻塞整个程序,即使看起来所有线程都应该同时运行。

于 2009-11-18T18:31:23.390 回答
5

正如之前的答案所述,go 例程不一定对应于系统线程,但是如果您现在必须提高多线程的性能,我发现以下内容很有用:

默认情况下,Go 运行时的当前实现不会并行化此代码。它仅将一个内核专用于用户级处理。在系统调用中可以阻塞任意数量的 goroutine,但默认情况下,任何时候只有一个可以执行用户级代码。它应该更智能,而且有一天它会更智能,但是在你想要 CPU 并行性之前,你必须告诉运行时你想要同时执行代码的 goroutine 数量. 有两种相关的方法可以做到这一点。将环境变量 GOMAXPROCS 设置为要使用的内核数运行您的作业,或者导入运行时包并调用 runtime.GOMAXPROCS(NCPU)。一个有用的值可能是 runtime.NumCPU(),它报告本地机器上逻辑 CPU 的数量。同样,随着调度和运行时间的改进,预计此要求将被淘汰。

报价来源

一个最大化我的 i5 处理器的示例程序是这个(在 htop 中以 100% 使用所有 4 个内核):

package main


import (
    "fmt"
    "time"
    "runtime"
)


func main() {
    runtime.GOMAXPROCS(4) // Set the maximum number of threads/processes

    d := make(chan string)
    go boring("boring!", d, 1)
    go boring("boring!", d, 2)
    go boring("boring!", d, 3)
    go boring("boring!", d, 4)

    for i := 0; i < 10; i++ {
        time.Sleep(time.Second);
    }

    fmt.Println("You're boring; I'm leaving.")
}

func boring(msg string, c chan string, id int) {
    for i := 0; ; i++ {

    }
}

现在这实际上并没有“做”任何事情,但看看与用其他语言(如 Java)编写多线程应用程序相比,它有多短/容易/简单。

于 2013-01-31T11:35:54.210 回答