I have next code:
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
}
}
I use next to run it:
$ go build par.go
$ time ./par
Then, confirm how many threads in this process:
$ 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
You can see there are 5 threads.
If I change the value of n
in code, then situations are next:
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
I know, go scheduler follow MPG
model, here P = 4
, so M = 4
, M
is 1:1
with KSE
(Kernel threads). If any goroutine in any blocking status, the P
will detached from current M
, and find a idle M
or new a M
if can't find.
So, my question is: is time.Sleep
really blocking goroutine? If not, why new threads there when I increase value of n
from 1
to 2000000
? If yes, there is 60 seconds
there, why just scheduler new a little new M
, I expect a lots of new threads there?
UPDATE:
Add another example from 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 {}
}
If not use Sleep
, use real IO, the threads number will be 202
on my machine.
So, my question also related to the difference of above 2 examples, when I should worry about scheduler generate too many kernel threads for me?
See Question&Answers more detail:
os