# Golang 标准库丨runtime
Package runtime contains operations that interact with Go's runtime system, such as functions to control goroutines. It also includes the low-level type information used by the reflect package; see reflect's documentation for the programmable interface to the run-time type system.
runtime 包包含与 Go 运行时系统交互的操作,比如控制 Goroutine 的函数。它还包括 reflect 包使用的底层类型信息。有关运行时类型系统的可编程接口,请参见 reflect 的文档。
尽管 Go 编译器产生的是本地可执行代码,这些代码仍旧运行在 Go 的 runtime(这部分的代码可以在 runtime 包中找到)当中。这个 runtime 类似 Java 和 .NET 语言所用到的虚拟机,它负责管理包括:
- 内存分配
- 垃圾回收
- 栈处理
- goroutine
- channel
- 切片(slice)
- map
- 反射(reflection)
- ...
# 一、常用函数
runtime
调度器是个非常有用的东西,关于 runtime
包几个方法:
NumCPU:返回当前系统的
CPU
核数量。GOMAXPROCS:设置最大的可同时使用的
CPU
核数。通过
runtime.GOMAXPROCS
函数,应用程序可以在运行期间设置运行时系统中得 P 最大数量。但这会引起
Stop the World
。所以,应在应用程序最早的调用。并且最好是在运行 Go 程序之前设置好操作程序的环境变量 GOMAXPROCS,而不是在程序中调用 runtime.GOMAXPROCS 函数。无论我们传递给函数的整数值是什么值,运行时系统的 P 最大值总会在 1~256 之间。
Go1.8 后,默认让程序运行在多个核上,可以不用设置了。 Go1.8 前,还是要设置一下,可以更高效的利用 CPU。
Gosched:让当前线程让出
CPU
以让其它线程运行,它不会挂起当前线程,因此当前线程未来会继续执行。这个函数的作用是让当前
goroutine
让出CPU
,当一个goroutine
发生阻塞,Go
会自动地把与该goroutine
处于同一系统线程的其他goroutine
转移到另一个系统线程上去,以使这些goroutine
不阻塞。Goexit:退出当前
goroutine
(但是defer
语句会照常执行)。NumGoroutine:返回正在执行和排队的任务总数。
runtime.NumGoroutine
函数在被调用后,会返回系统中的处于特定状态的 Goroutine 的数量。这里的特指是指Grunnable\Gruning\Gsyscall\Gwaition
。处于这些状态的 Groutine 即被看做是活跃的或者说正在被调度。注意:垃圾回收中所在 Goroutine 的状态也处于这个范围内的话,也会被纳入该计数器。
GC:会让运行时系统进行一次强制性的垃圾收集。
- 强制的垃圾回收:不管怎样,都要进行的垃圾回收。
- 非强制的垃圾回收:只会在一定条件下进行的垃圾回收(即运行时,系统自上次垃圾回收之后新申请的堆内存的单元(也成为单元增量)达到指定的数值)。
GOROOT :获取 $GOROOT 目录
GOOS : 查看目标操作系统。
很多时候,我们会根据平台的不同实现不同的操作,就可以用 GOOS 了。
Version:获取运行时 Go 版本
# 二、示例代码
获取 GOROOT 和 OS:
fmt.Println(runtime.GOOS) fmt.Println(runtime.GOROOT())
获取 CPU 数量,设置 CPU 数量:
fmt.Println(runtime.NumCPU()) runtime.GOMAXPROCS(runtime.NumCPU())
让出 CPU:
package main import ( "fmt" "runtime" ) func main() { go func() { for i := 0; i < 5; i++ { fmt.Println("Goroutine...") } }() for i := 0; i < 4; i++ { //让出时间片,先让别的协程执行,别的协程执行完,再回来执行此协程 runtime.Gosched() fmt.Println("main....") } }
输出:
Goroutine... Goroutine... Goroutine... Goroutine... Goroutine... main.... main.... main.... main....
终止协程:
package main import ( "fmt" "runtime" ) func main() { go func() { defer func() { fmt.Println("Goroutine defer...") }() for i := 0; i < 5; i++ { if i == 2 { runtime.Goexit() } fmt.Println("Goroutine...") } }() for i := 0; i < 4; i++ { //让出时间片,先让别的协程执行,别的协程执行完,再回来执行此协程 runtime.Gosched() fmt.Println("main....") } }
输出:
Goroutine... Goroutine... Goroutine defer... main.... main.... main.... main....
参考:
- https://golang.org/pkg/runtime/
- https://www.qfgolang.com/?special=bingfagoroutinechannel&pid=2077