通过 pprof 查看 go 程序的运行状况时,发现 threadcreate 总是 7 或者 8 为什么呢?
本机 runtime.NumCPU() = 4
code:
package main
import (
"fmt"
"log"
"net/http"
_ "net/http/pprof"
"runtime"
)
var c = make(chan int)
func init() {
for i:=0;i<10;i++{
go func(i int) {
fmt.Println("push : ",i)
c <- i
}(i)
}
}
func main() {
// 设置使用 cpu 的最大核数
runtime.GOMAXPROCS(1)
http.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) {
for i:=0;i<5;i++{
fmt.Println("pop : ",<-c)
}
writer.Write([]byte("hello world"))
})
log.Fatal( http.ListenAndServe(":8000",nil))
}
然后访问 http://localhost:8000/debug/pprof/threadcreate?debug=1,结果为:
threadcreate profile: total 7
6 @
# 0x0
1 @ 0x103ae7e 0x103b589 0x1037d44 0x1037d45 0x1067401
# 0x103ae7d runtime.allocm+0x14d /usr/local/go/go1.14.2/src/runtime/proc.go:1390
# 0x103b588 runtime.newm+0x38 /usr/local/go/go1.14.2/src/runtime/proc.go:1704
# 0x1037d43 runtime.startTemplateThread+0x2c3 /usr/local/go/go1.14.2/src/runtime/proc.go:1768
# 0x1037d44 runtime.main+0x2c4 /usr/local/go/go1.14.2/src/runtime/proc.go:186
哪位大佬给解释下,为什么是 7 个线程。 其中 6 @ 0x0 是什么呢
1
mainjzb 2020-04-30 14:56:25 +08:00
runtime.GOMAXPROCS(1) 这行应该放在 init()函数的开头调用。我的测试是 6 线程,估计是 http 创建了 5 个线程,另外 1 个是 goroutin
|
3
zzzzzzkd 2020-04-30 17:10:53 +08:00 via iPhone
runtime.GOMAXPROCS(1)设置的是 P 的数量
|
4
asAnotherJack 2020-04-30 17:25:58 +08:00
根据 GMP 模型,GOMAXPROCS 设置的是 P 的数量,限制同时运行的线程数,不是限制的 M 的数量,M 的最大数量可以看 src/runtime/runtime2.go 结构体 schedt 有个字段 maxmcount 注释 // maximum number of m's allowed (or die),默认是 10000,改的话可以通过 debug.SetMaxThreads,超过数量直接 crash 。
可以通俗理解一下,比如限制并发数为 1,如果只允许创建一个线程的话,当这个线程阻塞了,又不允许创建新线程,那并发就变 0 了,不合适的 不知道理解的对不对,等大佬解惑 |
5
xmge OP @asAnotherJack 在代码测试 debug.SetMaxThreads 的确超过后就有错误 ; runtime: program exceeds 3-thread limit
fatal error: thread exhaustion 。 感觉大佬解释很靠谱 |
6
xmge OP ```
func schedinit() { // raceinit must be the first call to race detector. // In particular, it must be done before mallocinit below calls racemapshadow. _g_ := getg() if raceenabled { _g_.racectx, raceprocctx0 = raceinit() } sched.maxmcount = 10000 tracebackinit() moduledataverify() stackinit() mallocinit() fastrandinit() // must run before mcommoninit mcommoninit(_g_.m) .. } ``` |
7
wysnylc 2020-04-30 18:30:22 +08:00
盲猜 cpu 虚拟核心数
|
8
mainjzb 2020-04-30 18:41:26 +08:00
```
package main import ( "fmt" "log" "net/http" _ "net/http/pprof" "runtime" ) var c = make(chan int) func init() { runtime.GOMAXPROCS(1) // 改成 50,线程数可以显著提升 for i:=0;i<100000;i++{ go func(i int) { fmt.Println("push : ",i) c <- i }(i) } } func main() { http.HandleFunc("/", func(writer http.ResponseWriter, request *http.Request) { writer.Write([]byte("hello world")) }) log.Fatal( http.ListenAndServe(":8000",nil)) } ``` |
9
kaifang 2020-04-30 18:47:14 +08:00
GPM 模型
G:Goruntine,待执行的 Goruntine 任务队列,分全局和本地 P: 本地调度器,运行在线程 M 上的本地调度器,持有 G M: 线程 runtime.GOMAXPROCS(1) 这个是逻辑上的核心数并不是物理上的核心数,也就是规定同时只有一个 P 会在线程 M 上去工作,至于线程 M 肯定是要有多个的,因为 G 阻塞之后 P 会找下一个 M 再进行调度运行 G 。核心数不是越多越好,一般默认是物理核心数。 可以参考: https://draveness.me/golang/docs/part3-runtime/ch06-concurrency/golang-goroutine/ https://www.bilibili.com/video/BV1g4411R7p5 |
10
mainjzb 2020-04-30 19:05:37 +08:00
The GOMAXPROCS variable limits the number of operating system threads that can execute user-level Go code simultaneously. There is no limit to the number of threads that can be blocked in system calls on behalf of Go code; those do not count against the GOMAXPROCS limit. This package's GOMAXPROCS function queries and changes the limit.
|
11
tairan2006 2020-05-01 07:48:45 +08:00 via Android
超线程技术
|