内容简介:尽管 Go 编译器产生的是本地可执行代码,这些代码仍旧运行在 Go 的 runtime(这部分的代码可以在 runtime 包中找到)当中。这个 runtime 类似 Java 和 .NET 语言所用到的虚拟机,它负责管理包括内存分配、垃圾回收(第 10.8 节)、栈处理、goroutine、channel、切片(slice)、map 和反射(reflection)等等。运行结果:
尽管 Go 编译器产生的是本地可执行代码,这些代码仍旧运行在 Go 的 runtime(这部分的代码可以在 runtime 包中找到)当中。这个 runtime 类似 Java 和 .NET 语言所用到的虚拟机,它负责管理包括内存分配、垃圾回收(第 10.8 节)、栈处理、goroutine、channel、切片(slice)、map 和反射(reflection)等等。
runtime
调度器是个非常有用的东西,关于 runtime
包几个方法:
-
Gosched:让当前线程让出
cpu
以让其它线程运行,它不会挂起当前线程,因此当前线程未来会继续执行 -
NumCPU:返回当前系统的
CPU
核数量 -
GOMAXPROCS:设置最大的可同时使用的
CPU
核数 -
Goexit:退出当前
goroutine
(但是defer
语句会照常执行) -
NumGoroutine:返回正在执行和排队的任务总数
-
GOOS:目标操作系统
NumCPU
package main import ( "fmt" "runtime" ) func main() { fmt.Println("cpus:", runtime.NumCPU()) fmt.Println("goroot:", runtime.GOROOT()) fmt.Println("archive:", runtime.GOOS) }
运行结果:
image.png
GOMAXPROCS
Golang
默认所有任务都运行在一个 cpu
核里,如果要在 goroutine
中使用多核,可以使用 runtime.GOMAXPROCS
函数修改,当参数小于 1 时使用默认值。
package main import ( "fmt" "runtime" ) func init() { runtime.GOMAXPROCS(1) } func main() { // 任务逻辑... }
Gosched
这个函数的作用是让当前 goroutine
让出 CPU
,当一个 goroutine
发生阻塞, Go
会自动地把与该 goroutine
处于同一系统线程的其他 goroutine
转移到另一个系统线程上去,以使这些 goroutine
不阻塞。
注意关闭通道使用的是 close()
方法。
引申思考:close()关闭通道的时候,如果关闭一个已经关闭的通道,会报错。那我们关闭时如何确定通道此时的状态呢?
这里有一篇文章大家可以参考下
https://www.jianshu.com/p/d24dfbb33781package 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 }
结果:
image.png
使用多核测试:
package main import ( "fmt" "runtime" ) func init() { runtime.GOMAXPROCS(4) //使用多核 } 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 }
结果:
image.png
根据你机器来设定运行时的核数,但是运行结果不一定与上面相同,或者在 main
函数的最后加上 select{} 让程序阻塞,则结果如下:
image.png
多核比较适合那种 CPU
密集型程序,如果是 IO
密集型使用多核会增加 CPU
切换的成本。
Gosched再说明
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") }
输出结果:
hello
world
hello
注意结果:
1、先输出了hello,后输出了world.
2、hello输出了2个,world输出了1个(因为第2个hello输出完,主线程就退出了,第2个world没机会了)
把代码中的runtime.Gosched()注释掉,执行结果是:
hello
hello
因为say("hello")这句占用了时间,等它执行完,线程也结束了,say("world")就没有机会了。
这里同时可以看出,go中的goroutins并不是同时在运行。事实上,如果没有在代码中通过
runtime.GOMAXPROCS(n) 其中n是整数,
指定使用多核的话,goroutins都是在一个线程里的,它们之间通过不停的让出时间片轮流运行,达到类似同时运行的效果。
以上所述就是小编给大家介绍的《golang中的runtime包教程》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- 立体字母建模教程【C4D教程】
- PS学习教程 PS制作字体发光效果教程
- 【C4D教程】卡通风可爱小乌龟建模教程
- 卡通风仙人掌建模教程【C4D教程】
- 3D立体字体制作教程,C4D建模教程
- 3D小乌龟制作教程,C4D建模教程
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。