The documentation for runtime.LockOsThread
声明:
LockOSThread将调用goroutine连接到其当前操作系统线程。在调用goroutine退出或调用UnlockOSThread之前,它将始终在该线程中执行,而其他任何goroutine都无法执行。
但考虑一下这个项目:
package main
import (
"fmt"
"runtime"
"time"
)
func main() {
runtime.GOMAXPROCS(1)
runtime.LockOSThread()
go fmt.Println("This shouldn't run")
time.Sleep(1 * time.Second)
}
main
goroutine连接到GOMAXPROCS
设置的一个可用OS线程,因此我预计在main
第3行上创建的goroutine不会运行。但相反,程序打印This shouldn't run
,暂停1秒,然后退出。这一切为什么要发生?
发布于 2016-05-24 20:08:54
GOMAXPROCS变量限制可以同时执行用户级Go代码的操作系统线程的数量。代表Go代码在系统调用中可以阻塞的线程数量没有限制;这些线程不包括GOMAXPROCS限制.
休眠线程不计算为1的GOMAXPROCS
值,因此Go可以自由地让另一个线程运行fmt.Println
goroutine。
发布于 2016-05-25 06:25:33
这里有一个Windows示例,它可能会帮助您了解正在发生的事情。它打印运行goroutines的线程It。必须使用syscall,所以它只能在Windows上工作。但您可以轻松地将其移植到其他系统。
package main
import (
"fmt"
"runtime"
"golang.org/x/sys/windows"
)
func main() {
runtime.GOMAXPROCS(1)
runtime.LockOSThread()
ch := make(chan bool, 0)
go func(){
fmt.Println("2", windows.GetCurrentThreadId())
<- ch
}()
fmt.Println("1", windows.GetCurrentThreadId())
<- ch
}
我不使用睡眠来防止运行时生成另一个用于睡眠猩猩的线程。通道将阻塞并移除运行队列中的goroutine。如果执行代码,您将看到线程ID是不同的。主goroutine锁定了其中一个线程,因此运行时必须生成另一个线程。
正如您已经知道的,GOMAXPROCS
并不阻止运行时生成更多的线程。GOMAXPROCS
是关于可以并行执行goroutines的线程数的更多信息。但是可以为等待syscall完成的goroutines创建更多的线程,例如。
如果删除runtime.LockOSThread()
,您将看到线程ID是相等的。这是因为通道读取阻止了goroutine,并允许运行时将执行交付给另一个goroutine,而无需生成新线程。这就是即使在GOMAXPROCS
为1时多个goroutines也可以并发执行的方式。
发布于 2020-09-16 16:08:59
GOMAXPROCS(1),它会使您有一个活动的M (OS线程)来服务器go例程(G)。
在您的程序中有两个Go例程,一个是main
,另一个是fmt.Println
。由于main
例程处于睡眠状态,M可以自由运行任何go例程,在本例中,fmt.Println
可以运行这些例程。
https://stackoverflow.com/questions/37426511
复制相似问题