golang中的runtime包教程
豆瓣奶茶 · · 20801 次点击 · · 开始浏览尽管 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)
}
运行结果:
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/d24dfbb33781
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
}
结果:
使用多核测试:
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
}
结果:
根据你机器来设定运行时的核数,但是运行结果不一定与上面相同,或者在 main 函数的最后加上 select{} 让程序阻塞,则结果如下:
多核比较适合那种 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都是在一个线程里的,它们之间通过不停的让出时间片轮流运行,达到类似同时运行的效果。
有疑问加站长微信联系(非本文作者)
入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889
关注微信- 请尽量让自己的回复能够对别人有帮助
- 支持 Markdown 格式, **粗体**、~~删除线~~、
`单行代码` - 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
- 图片支持拖拽、截图粘贴等方式上传
收入到我管理的专栏 新建专栏
尽管 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)
}
运行结果:
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/d24dfbb33781
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
}
结果:
使用多核测试:
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
}
结果:
根据你机器来设定运行时的核数,但是运行结果不一定与上面相同,或者在 main 函数的最后加上 select{} 让程序阻塞,则结果如下:
多核比较适合那种 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都是在一个线程里的,它们之间通过不停的让出时间片轮流运行,达到类似同时运行的效果。