gpt4 book ai didi

go - 在使用 GOMAXPROCS = 256 运行无限循环 goroutines 时理解 golang 的调度程序

转载 作者:数据小太阳 更新时间:2023-10-29 03:26:15 24 4
gpt4 key购买 nike

我正在玩 Go,在我的 2015 8 核 MacBookPro 上运行 go 1.7.3。

尝试了解 runtime.GOMAXPROCS 设置为其最大值 (256) 并启动相同数量的 goroutine 时 go scheduler 的工作原理,每个 goroutine 都运行一个无限循环。

我的假设是 go runtime 会产生 runtime.GOMAXPROCS 数量的操作系统线程(即 256 个线程)并在这些线程中运行我的 goroutines。

我期待下面的代码打印出 256 个 1:

func main() {
procs := 256
runtime.GOMAXPROCS(procs)
for i := 0; i < procs; i++ {
go func() {
fmt.Print("1")
for {}
}()
}
for {}
}

此代码每次运行时都会打印不同数量的 1。大多数时候它会打印 142 个 1。

现在,有手动调用 go scheduler 的 runtime.Gosched()。我正在玩它,发现只有当我在两个 goroutines main func 中调用 runtime.Gosched() 时,我才能打印 256 个 1:

func main() {
procs := 256
runtime.GOMAXPROCS(procs)
for i := 0; i < procs; i++ {
go func() {
fmt.Print("1")
for { runtime.Gosched() }
}()
}
for { runtime.Gosched() }
}

有人可以解释为什么默认情况下不打印 256 个 1 而我需要 runtime.Gosched() 吗?我们不应该得到 256 个操作系统线程来运行这 256 个 goroutines 吗?为什么我们需要在两个地方调用 runtime.Gosched()?

最佳答案

我认为这是因为您可以在您的机器上创建的线程有限制。runtime.GOMAXPROCS(256) 所做的是创建 256 个逻辑处理器 (也称为 P = Proccesor)并尝试运行它们。每个 P 都有自己的名为 G 的 goroutines 运行队列,并由操作系统线程(称为 M 作为机器)执行。

那么发生的情况是,您的 256 个 P 试图让操作系统线程 (M) 执行 G,但您的计算机没有没有那么多资源来运行 256 个操作系统线程,所以这就是为什么你只得到 143 个。

对我来说,执行此命令会产生 143 个,此进程的运行线程数约为 150。

因为默认情况下 go scheduler 不会抢占任何 goroutines 你只会运行大约 150 个 goroutines 而所有其他的 goroutines 都将缺乏操作系统线程。这是一个 issue描述这种行为。调用 runtime.Gosched() 产生处理器 (P),允许其他 goroutines 运行。

要检查调度程序正在做什么,您可以添加 GODEBUG 环境变量:

env GODEBUG=scheddetail=1,schedtrace=1000 ./cpu3

这是输出(注意它使用了P、M、G 术语):

SCHED 0ms: gomaxprocs=8 idleprocs=5 threads=5 spinningthreads=1 idlethreads=0 runqueue=0 gcwaiting=0 nmidlelocked=1 stopwait=0 sysmonwait=0
P0: status=1 schedtick=0 syscalltick=0 m=3 runqsize=0 gfreecnt=0
P1: status=1 schedtick=1 syscalltick=0 m=2 runqsize=0 gfreecnt=0
P2: status=1 schedtick=0 syscalltick=0 m=4 runqsize=0 gfreecnt=0
P3: status=0 schedtick=0 syscalltick=0 m=-1 runqsize=0 gfreecnt=0
P4: status=0 schedtick=0 syscalltick=0 m=-1 runqsize=0 gfreecnt=0
P5: status=0 schedtick=0 syscalltick=0 m=-1 runqsize=0 gfreecnt=0
P6: status=0 schedtick=0 syscalltick=0 m=-1 runqsize=0 gfreecnt=0
P7: status=0 schedtick=0 syscalltick=0 m=-1 runqsize=0 gfreecnt=0
M4: p=2 curg=-1 mallocing=0 throwing=0 preemptoff= locks=1 dying=0 helpgc=0 spinning=true blocked=false lockedg=-1
M3: p=0 curg=-1 mallocing=0 throwing=0 preemptoff= locks=1 dying=0 helpgc=0 spinning=false blocked=false lockedg=-1
M2: p=1 curg=-1 mallocing=0 throwing=0 preemptoff= locks=1 dying=0 helpgc=0 spinning=true blocked=false lockedg=-1
M1: p=-1 curg=-1 mallocing=0 throwing=0 preemptoff= locks=1 dying=0 helpgc=0 spinning=false blocked=false lockedg=-1
M0: p=-1 curg=-1 mallocing=0 throwing=0 preemptoff= locks=0 dying=0 helpgc=0 spinning=false blocked=true lockedg=1
G1: status=1(chan receive) m=-1 lockedm=0
G2: status=4(force gc (idle)) m=-1 lockedm=-1
G3: status=4(GC sweep wait) m=-1 lockedm=-1
1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111SCHED 1004ms: gomaxprocs=256 idleprocs=0 threads=150 spinningthreads=0 idlethreads=5 runqueue=0 gcwaiting=1 nmidlelocked=0 stopwait=143 sysmonwait=0
P0: status=1 schedtick=1 syscalltick=3 m=0 runqsize=0 gfreecnt=0
P1: status=1 schedtick=3 syscalltick=1 m=2 runqsize=0 gfreecnt=0
...
P141: status=1 schedtick=3 syscalltick=1 m=143 runqsize=0 gfreecnt=0
P142: status=1 schedtick=2 syscalltick=3 m=144 runqsize=0 gfreecnt=0
P143: status=3 schedtick=1 syscalltick=38 m=-1 runqsize=0 gfreecnt=0
...
P255: status=3 schedtick=0 syscalltick=0 m=-1 runqsize=0 gfreecnt=0
M149: p=-1 curg=-1 mallocing=0 throwing=0 preemptoff= locks=0 dying=0 helpgc=0 spinning=false blocked=true lockedg=-1
...
M144: p=142 curg=181 mallocing=0 throwing=0 preemptoff= locks=0 dying=0 helpgc=0 spinning=false blocked=false lockedg=-1
M143: p=141 curg=177 mallocing=0 throwing=0 preemptoff= locks=0 dying=0 helpgc=0 spinning=false blocked=false lockedg=-1
M142: p=140 curg=179 mallocing=0 throwing=0 preemptoff= locks=0 dying=0 helpgc=0 spinning=false blocked=false lockedg=-1
...
M112: p=110 curg=186 mallocing=0 throwing=0 preemptoff= locks=0 dying=0 helpgc=0 spinning=false blocked=false lockedg=-1
...

关于go - 在使用 GOMAXPROCS = 256 运行无限循环 goroutines 时理解 golang 的调度程序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40943591/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com