Golang中runtime的使用
Golang中runtime的使用
runtime调度器是非常有用的东西,关于runtime包几个方法:
-
Gosched:让当前线程让出cpu以让其他线程运行,它不会挂起当前线程,因此当前线程未来会继续执行
-
NumCPU:返回当前系统的CPU核数量
-
GOMAXPROCS:设置最大的可同时使用的CPU核数
-
Goexit:退出当前goroutine(但是defer语句会照常执行)
-
NumGoroutine:返回真该执行和排队的任务总数
-
GOOS:目标操作系统
package main
import "fmt"
import "runtime"func main(){
fmt.Println("cpus:", runtime.NumCPU())
fmt.Println("goroot:", runtime.GOROOT())
fmt.Println("NumGoroutine:", runtime.NumGoroutine())
fmt.Println("archive:", runtime.GOOS)
}
运行结果:
$ ./test
cpus: 4
goroot: D:\Go\
NumGoroutine: 1
archive: windows
GOMAXPROCS
Golang默认所有任务都运行在一个cpu核里,如果要在goroutine中使用多核,可以使用runtime.GOMAXPROCS函数修改,当参数小于1时使用默认值。
package main
import "fmt"
import "runtime"
import "time"
func init(){
runtime.GOMAXPROCS(4)
}
func main(){
t := time.Now().Nanosecond()
for i:=0;i<100000;i++{
fmt.Println(i*i*i*i)
}
t2 := time.Now().Nanosecond()
fmt.Println(t2-t)
}
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
}
在windows系统上,结果为:
a: 0
a: 1
a: 2
a: 3
切换成多核,每次运行的结果都不一样:
package main
import (
"fmt"
"runtime"
)
func main() {
runtime.GOMAXPROCS(4)
exit := make(chan int)
go func() {
defer close(exit)
go func() {
fmt.Println("b")
}()
}()
for i := 0; i < 10; i++ {
fmt.Println("a:", i)
if i == 4 {
runtime.Gosched() //切换任务
}
}
<-exit
}
总结:多核比较适合那种CPU密集型程序,如果是IO密集型使用多核会增加CPU切换的成本。
GOMAXPROCS和sync配合使用
sync.WaitGroup只有三个方法,Add(),Done()和Wait()。其中Done()是Add(-1)的别名。简单来说,使用ADdd()添加计数,Done()减少一个计数,技术不为0,阻塞Wait()的运行。
package main
import (
"runtime"
"sync"
"fmt"
)
func main(){
runtime.GOMAXPROCS(2)
var wg sync.WaitGroup
wg.Add(2)
fmt.Printf("Starting go routines")
go func(){
defer wg.Done()
for char := 'a';char<'a'+26;char++{
fmt.Printf("%c",char)
}
}()
go func() {
defer wg.Done()
for number := 1;number<27;number++{
fmt.Printf("%d",number)
}
}()
fmt.Println("\nWaiting to finish")
wg.Wait()
fmt.Println("\n terminating program")
}
运行结果:
$ go run main.go
Starting go routines
Waiting to finish
abcdefghijklmnopqrstuvwxyz1234567891011121314151617181920212223242526
terminating program
总结:首先是wg.Add(2)计数为2,阻塞wg.Wait()的运行,然后是wg.Done()减少计数到0,放开wg.Wait()的运行。