Go的多线程和pthread或Java线程有什么区别?

huangapple go评论113阅读模式
英文:

What is the difference between Go's multithreading and pthread or Java Threads?

问题

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

英文:

What is the difference between Go's multithreading approach and other approaches, such as pthread, boost::thread or Java Threads?

答案1

得分: 28

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

> Goroutines根据需要在系统线程上进行多路复用。
> 当一个goroutine执行阻塞的系统调用时,没有其他goroutine被阻塞。
>
> 我们将在某个时候对CPU绑定的goroutines执行相同的操作,
> 但是目前,如果您想要用户级并行性,
> 您必须设置$GOMAXPROCS或调用runtime.GOMAXPROCS(n)。

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

多个goroutine可能在需要时被多路复用到单个线程中。

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

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

英文:

Quoted from Day 3 Tutorial <- read this for more information.

> Goroutines are multiplexed as needed
> onto system threads. When a goroutine
> executes a blocking system call, no
> other goroutine is blocked.
>
> We will do the same for CPU-bound
> goroutines at some point, but for now,
> if you want user-level parallelism you
> must set $GOMAXPROCS. or call
> runtime.GOMAXPROCS(n).

A goroutine does not necessarily correspond to an OS thread. It can have smaller initial stack size and the stack will grow as needed.

Multiple gorouitines may be multiplexed into a single thread when needed.

More importantly, the concept is as outlined above, that a goroutine is a sequential program that may block itself but does not block other goroutines.

Goroutines is implemented as pthreads in gccgo, so it can be identical to OS thread, too.
It's separating the concept of OS thread and our thinking of multithreading when programming.

答案2

得分: 13

在我看来,Go语言中多线程的吸引之处在于其通信设施:与pthread不同,我们不需要构建通信基础设施(如互斥锁、队列等),在Go语言中,这些设施默认就可方便地使用。

简而言之,由于良好的通信设施(类似于Erlang),使用线程的摩擦力较低

英文:

IMO, what makes the multi-threading in Go appealing is the communication facilities: unlike pthread where one must build the communications infrastructure (mutex, queues etc.), in Go it is available by default in a convenient form.

In short, there is "low-friction" to using threads because of the good communication facilities (akin to Erlang if I can say so).

答案3

得分: 12

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

调度在所有意义上都是使用协程实现的。相同的功能可以使用setjmp()和longjmp()在纯C中编写,Go(以及其他实现轻量级/绿色线程的语言)只是为您自动化了这个过程。

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

英文:

In the reference compilers (5g/6g/8g), the master scheduler (src/pkg/runtime/proc.c) creates N OS threads, where N is controlled by runtime.GOMAXPROCS(n) (default 1). Each scheduler thread pulls a new goroutine off the master list and starts running it. The goroutine(s) will continue to run until a syscall is made (e.g. printf) or an operation on a channel is made, at which point the scheduler will grab the next goroutine and run it from the point at which it left off (see gosched() calls in src/pkg/runtime/chan.c).

The scheduling, for all intents and purposes, is implemented with coroutines. The same functionality could be written in straight C using setjmp() and longjmp(), Go (and other languages that implement lightweight/green threads) are just automating the process for you.

The upside to lightweight threads is since it's all userspace, creating a "thread" is very cheap (allocating a small default stack) and can be very efficient due to the inherent structure of how the threads talk to eachother. The downside is that they are not true threads which means a single lightweight thread can block the entire program, even when it appears all the threads should be running concurrently.

答案4

得分: 5

如前面的答案所述,Go协程不一定对应系统线程,但如果您现在必须要获得多线程的性能提升,我发现以下方法很有用:

当前的Go运行时实现默认不会并行化这段代码。它只为用户级处理分配一个核心。任意数量的协程可以在系统调用中被阻塞,但默认情况下,只能有一个协程在执行用户级代码。它应该更加智能,总有一天会更加智能,但在此之前,如果您想要CPU并行性,必须告诉运行时有多少个协程同时执行代码。有两种相关的方法可以做到这一点。要么使用环境变量GOMAXPROCS设置要使用的核心数,要么导入runtime包并调用runtime.GOMAXPROCS(NCPU)。一个有用的值可能是runtime.NumCPU(),它报告了本地机器上的逻辑CPU数量。再次强调,随着调度和运行时的改进,这个要求有望被废除。

以下是一个将我的i5处理器的性能发挥到极致的示例程序(在htop中使用了全部4个核心的100%):

package main


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


func main() {
    runtime.GOMAXPROCS(4) // 设置最大线程/进程数

    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)中编写多线程应用程序的简短/简单/简洁程度。

英文:

As previous answers have stated, go routines do not necessarily correspond to system threads however I found the following useful if you must have the performance increase of multi-threading right now:

> The current implementation of the Go runtime will not parallelize this code by default. It dedicates only a single core to user-level processing. An arbitrary number of goroutines can be blocked in system calls, but by default only one can be executing user-level code at any time. It should be smarter and one day it will be smarter, but until it is if you want CPU parallelism you must tell the run-time how many goroutines you want executing code simultaneously. There are two related ways to do this. Either run your job with environment variable GOMAXPROCS set to the number of cores to use or import the runtime package and call runtime.GOMAXPROCS(NCPU). A helpful value might be runtime.NumCPU(), which reports the number of logical CPUs on the local machine. Again, this requirement is expected to be retired as the scheduling and run-time improve.

quote source

An example program that maxes out my i5 processor is this (uses all 4 cores at 100% in htop):

package main


import (
    &quot;fmt&quot;
    &quot;time&quot;
    &quot;runtime&quot;
)


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

    d := make(chan string)
    go boring(&quot;boring!&quot;, d, 1)
    go boring(&quot;boring!&quot;, d, 2)
    go boring(&quot;boring!&quot;, d, 3)
    go boring(&quot;boring!&quot;, d, 4)
    
    for i := 0; i &lt; 10; i++ {
	    time.Sleep(time.Second);
    }

    fmt.Println(&quot;You&#39;re boring; I&#39;m leaving.&quot;)
}

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

Now that doesn't actually 'do' anything, but see how short/easy/simple that is compared to writing multithreaded applications in other languages such as Java.

huangapple
  • 本文由 发表于 2009年11月16日 09:33:39
  • 转载请务必保留本文链接:https://go.coder-hub.com/1739614.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定