所以我有一个程序需要分配一大块内存并永远保存它。作为测试,我还运行了一个运行无限循环的 goroutine,在我的主线程中,我分配了内存,但是即使我将 GOMAXPROCS 设置为大于 1,程序也会永远卡在 goroutine 的无限循环中。
func main() {
runtime.GOMAXPROCS(2)
go func() {
for {
//fmt.Printf("goroutine1\n")
}
}()
fmt.Println("main thread1")
x := [1145][1145]int{}
for i := 0; i < 1144; i++ {
fmt.Println(i)
x[i][i] = i
}
fmt.Println("main thread2")
}
如果我在无限循环中不做任何事情,我的主线程 1 将永远无法成功分配内存并打印“主线程 2”,即使我将 GOMAXPROCS 设置为 2,如果我在无限循环中打印一些东西,一切正常(这是预期的,因为 goroutine 在无限循环中打印一些东西,它调用系统调用并产生 cpu,所以我的主线程可以分配内存。
我想知道为什么会这样?
最佳答案
你的底层计算机系统有一些线程执行器。 Go 运行时自己找出有多少,并创建适当数量的运行时执行程序以使用所有系统。更改 GOMAXPROCS 会更改运行时尝试分配的执行程序数量,但对底层系统没有影响。在这种情况下,似乎底层系统本身只有一个执行者。
如果你的底层系统有两个或更多,那么 Go 已经创建了两个执行器,并且会在其中一个上运行无限循环 goroutine,而你的 main
另一方面,goroutine 同时。但是由于您的系统只有一个,所以只有一个可以运行。无论 Go 运行时可能创建多少运行时级别的执行程序,只有一个可以绑定(bind)到硬件 CPU 以实际运行。
请注意,goroutine 是多对 N 映射的。例如,假设您拆分出 1000 个 goroutine,并拥有 10 个 CPU。运行时将分配 10 个执行器并使用 10 个 CPU 一次运行 1000 个 goroutine 中的 10 个。剩下的 990 个 goroutine 等到其中一个执行者达到自愿停止运行该 goroutine 并选择剩余 990 个的点。
您可以调用 runtime.Gosched
你自己,从任何 goroutine 说:我自愿暂停自己,让其他想要运行的 goroutine 运行,直到执行者可以接我再次运行。许多其他系统调用此函数yield
或一些变化。 (注意“暂停”这个词:我在这里使用它是为了生效,但是调用 runtime.Gosched
的 goroutine 在技术上并没有暂停,因为它仍然被标记为“想要运行”,而其他 goroutine 可能在技术上被暂停因为它们被标记为“现在不能运行,正在等待____”(填空)。)
另见 How do goroutines work? (or: goroutines and OS threads relation) .
关于go - 关于goroutine无限循环和内存分配的问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58648083/