尽管 Go 编译器产生的是本地可执行代码,这些代码仍旧运行在 Go 的 runtime(这部分的代码可以在 runtime 包中找到)当中。这个 runtime 类似 Java 和 .NET 语言所用到的虚拟机,它负责管理包括内存分配、垃圾回收(第 10.8 节)、栈处理、goroutine、channel、切片(slice)、map 和反射(reflection)等等。
系统信息
runtime.GOARCH // CPU架构runtime.NumCPU() // CPU数量runtime.GOOS // 操作系统名称runtime.GOROOT() // GOROOTruntime.Version() // go 版本runtime.NumGoroutine() // 启动的goroutine数
GOMAXPROCS
Golang 默认所有任务都运行在一个 cpu 核里,如果要在 goroutine 中使用多核,可以使用 runtime.GOMAXPROCS 函数修改,当参数小于 1 时使用默认值。
Gosched
这个函数的作用是让当前 goroutine 让出 CPU,当一个 goroutine 发生阻塞,Go 会自动地把与该 goroutine 处于同一系统线程的其他 goroutine 转移到另一个系统线程上去,以使这些 goroutine 不阻塞。
package mainimport ("fmt""runtime")func init() {runtime.GOMAXPROCS(1) //使用单核}func main() {exit := make(chan int)go func() {defer close(exit)go func() {fmt.Println("b")}()}()for i := 0; i < 4; i++ {fmt.Println("a:", i)if i == 1 {runtime.Gosched() // 切换任务}}<-exit}
output
go run main.goa: 0a: 1ba: 2a: 3
多核比较适合那种
CPU密集型程序,如果是IO密集型使用多核会增加CPU切换的成本。
Gosched用来让出CPU的时间片。就像是接力赛跑,A跑了一会碰到runtime.Gosched(),就会把时间片给B,让B接着跑。
package mainimport ("runtime""fmt")func init() {runtime.GOMAXPROCS(1)}func say(s string){for i := 0; i < 2; i++ {runtime.Gosched()fmt.Println(s)}}func main() {go say("world")say("hello")}
注意结果:
1、先输出了hello,后输出了world.
2、hello输出了2个,world输出了1个(因为第2个hello输出完,主线程就退出了,第2个world没机会了)
把代码中的runtime.Gosched()注释掉,执行结果是:
hellohello
因为say(“hello”)这句占用了时间,等它执行完,线程也结束了,say(“world”)就没有机会了。
这里同时可以看出,go中的goroutins并不是同时在运行。事实上,如果没有在代码中通过
