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