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()的运行。

你可能感兴趣的:(Golang中runtime的使用)