goroutines如何工作? (或者:goroutines和OS线程关系)
其他例程在调用系统调用时如何继续执行? (使用GOMAXPROCS = 1时)
据我所知,当调用系统调用时,线程放弃控制,直到系统调用返回。 如何在不通过阻塞系统调用goroutine创build系统线程的情况下实现这种并发性?
从文档 :
够程
它们被称为goroutines,因为现有的术语(线程,协程,进程等等)传递的是不准确的内涵。 goroutine有一个简单的模型:它是一个在同一个地址空间中与其他goroutines同时执行的函数。 它是轻量级的,比堆栈空间的分配花费更多。 堆栈起点很小,所以它们很便宜,而且根据需要分配(并释放)堆存储空间以增加堆栈。
Goroutines被多路复用到多个OS线程,所以如果应该阻塞,比如在等待I / O的时候,其他的继续运行。 他们的devise隐藏了许multithreading创build和pipe理的复杂性。
如果一个goroutine被阻塞,运行时将启动一个新的OS线程来处理其他的goroutines,直到阻塞的阻塞。
参考: https : //groups.google.com/forum/#!topic/golang- nuts/ 2IdA34yR8gQ
好吧,这就是我所学到的:当你在做原始的系统调用时,Go确实会创build一个阻塞goroutine的线程。 例如,请考虑以下代码:
package main import ( "fmt" "syscall" ) func block(c chan bool) { fmt.Println("block() enter") buf := make([]byte, 1024) _, _ = syscall.Read(0, buf) // block on doing an unbuffered read on STDIN fmt.Println("block() exit") c <- true // main() we're done } func main() { c := make(chan bool) for i := 0; i < 1000; i++ { go block(c) } for i := 0; i < 1000; i++ { _ = <-c } }
运行时,Ubuntu 12.04报告了1004个线程。
另一方面,当使用Go的HTTP服务器并打开1000个套接字时,只有4个操作系统线程被创build:
package main import ( "fmt" "net/http" ) func handler(w http.ResponseWriter, r *http.Request) { fmt.Fprintf(w, "Hi there, I love %s!", r.URL.Path[1:]) } func main() { http.HandleFunc("/", handler) http.ListenAndServe(":8080", nil) }
所以,这是IOLoop和每个阻塞系统调用的线程之间的混合。
它不能。 GOMAXPROCS = 1的时候只有一个goroutine可以运行,不pipe这个goroutine是在做一个系统调用还是其他的东西。
但是,从Go执行时,大多数阻塞系统调用,例如套接字I / O,等待定时器在系统调用中都不会被阻塞。 它们被Go运行时复用到epoll,kqueue或OS提供的用于复用I / O的类似工具上。
对于其他types的阻塞系统调用,不能用epoll进行多路复用,不pipeGOMAXPROCS设置如何(尽pipe这是Go 1.1中的状态,我不确定情况是否改变),Go会产生一个新的OS线程,
您必须区分处理器号和线程号:您可以拥有比物理处理器更多的线程,因此multithreading进程仍然可以在单个核心处理器上执行。
正如你所引用的文档所解释的那样,一个goroutine不是一个线程:它只是一个在专用于一堆栈空间的线程中执行的函数。 如果你的进程有多个线程,这个函数可以由任一线程执行。 因此,一个阻塞原因或其他(系统调用,I / O,同步)的goroutine可以放在其线程中,而其他例程可以由另一个例程执行。