【发布时间】:2020-06-23 05:08:20
【问题描述】:
我有下一个代码:
par.go
package main
import (
"runtime";
"time"
)
func main() {
runtime.GOMAXPROCS(4)
ch := make(chan int)
n := 1
for i := 0; i < n; i++ {
go func() {
time.Sleep(60 * time.Second)
ch <- 1
}();
}
for i := 0; i < n; i++ {
<-ch
}
}
我使用 next 来运行它:
$ go build par.go
$ time ./par
然后,确认这个进程有多少线程:
$ ps -ef | grep par
shubunt+ 3670 32131 0 12:35 pts/0 00:00:00 ./par
$ cat /proc/3670/status | grep -i threads
Threads: 5
你可以看到有 5 个线程。
如果我在代码中更改n 的值,那么情况如下:
n := 100, Threads is 8
n := 10000, Threads is 9
n := 100000, Threads is 9
n := 1000000, Threads is 9
n := 2000000, Threads is 10
我知道,去调度器遵循MPG 模型,这里是P = 4,所以M = 4,M 是1:1 和KSE(内核线程)。如果任何 goroutine 处于任何阻塞状态,P 将与当前的M 分离,并找到一个空闲的M,如果找不到则新的M。
所以,我的问题是:time.Sleep 真的会阻塞 goroutine 吗?如果没有,当我将n 的值从1 增加到2000000 时,为什么会有新线程?如果是,那里有60 seconds,为什么只是调度程序新一点点M,我希望那里有很多新线程?
更新:
添加来自this 的另一个示例。
test.go:
package main
import (
"io/ioutil"
"os"
"runtime"
"strconv"
)
func main() {
runtime.GOMAXPROCS(2)
data := make([]byte, 128*1024*1024)
for i := 0; i < 200; i++ {
go func(n int) {
for {
err := ioutil.WriteFile("testxxx"+strconv.Itoa(n), []byte(data), os.ModePerm)
if err != nil {
println(err)
break
}
}
}(i)
}
select {}
}
如果不使用Sleep,则使用真正的IO,我机器上的线程数将是202。
那么,我的问题也与上面两个例子的区别有关,什么时候我应该担心调度程序为我生成太多的内核线程?
【问题讨论】:
标签: go