gpt4 book ai didi

go - time.Sleep 会阻塞 goroutine 吗?

转载 作者:行者123 更新时间:2023-12-01 22:39:22 26 4
gpt4 key购买 nike

我有下一个代码:
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 , M1:1KSE (内核线程)。如果任何 goroutine 处于任何阻塞状态, P将脱离当前 M ,并找到一个空闲的 M或新的 M如果找不到。
所以,我的问题是:是 time.Sleep真的阻塞 goroutine?如果不是,为什么当我增加 n 的值时会有新线程来自 12000000 ?如果是,有 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在我的机器上。
所以,我的问题也与上面两个例子的区别有关,什么时候我应该担心调度程序为我生成太多的内核线程?

最佳答案

[I]s time.Sleep really blocking goroutine?


是的。
但是如何将 goroutine 实际调度到线程是 a) 复杂的,b) 在每个版本中都不同,c) 可能因架构而异,并且 d) 不是由语言指定的。虽然“MPG 模型”是一个准确的模型,但如果调度程序如何工作,它只是一个模型。
如果调度器确定 10 个线程足以不运行 200'000 个 goroutine,因为它们都是 time.Sleep然后 10 个线程就足够了。
基本上,在 Go 中没有什么可担心或考虑这些事情的(与其他必须特别注意这些特性的语言形成鲜明对比)。 “阻塞”只是意味着无法立即执行下一条语句,因为实际语句尚未完成喷射。如果原因很多,这可能会发生。除了等待之外什么都不做的 sleep ,等待内存,等待磁盘或等待网络数据。以相同的方式处理所有内容会简化调度程序,但会使调度程序变得很糟糕。所以不,time.Sleep 不会阻塞 goroutine。问题是“block goroutine”没有明确的含义。它不需要定义,因为没有什么有趣的东西可以知道。
更新:

[W]hen I should worry about scheduler generate too many kernel threads for me?


绝不。
有两种不同的场景:A) 编写正常的、合理的生产代码和 B) 编写精心设计的手工代码,以创建大量线程,这些线程都在磁盘 IO 中等待完成。当然,您可以故意欺骗调度程序和操作系统,并提出一个创建过多线程的病态程序(调度程序可能被欺骗的问题在 issue #4056 中得到解决),但这并不值得担心。只是不要故意做愚蠢的事情。
有很多方法可以欺骗您的计算机。编写活泼的代码是一种方法。种族检测器有助于识别它们。在编写它们之前担心竞争条件是一件好事(发生这种情况)。创建太多线程可能会发生,您可以向操作系统询问线程数。万一有太多:修复它。但这是 不太可能 .它有点像 OOM 错误:编写 OOM 的代码非常简单,但在编写代码时无需经常担心 OOM。如果您遇到 OOM,您会重新设计,但您不会因为担心 OOM 以及您需要了解 OOM、如何预防以及如何处理 OOM 而开始任何琐碎的项目。除非您已经知道您的数据使用大量内存。同样在这里:如果您知道您的代码将执行 大量 并发磁盘 IO 并且这是域固有的,那么您可能会担心这一点并在代码中处理它,但每种语言的技术都是相同的。

关于go - time.Sleep 会阻塞 goroutine 吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62527705/

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