golangCoding 经纬

讲讲go中runtime包中三个方法Gosched、Goexit

2021-08-03  本文已影响0人  小ocean
go 中runtime 类似 Java 和 .NET 语言所用到的虚拟机,它负责管理包括内存分配、垃圾回收、栈处理、goroutine、channel、切片(slice)、map 和反射(reflection)等等。

runtime 调度器是个非常有用的东西,关于 runtime 包几个方法:

.Gosched:让当前线程让出 cpu 以让其它线程运行,它不会挂起当前线程,因此当前线程未来会继续执行
.NumCPU:返回当前系统的 CPU 核数量
.GOMAXPROCS:设置最大的可同时使用的 CPU 核数
.Goexit:退出当前 goroutine(但是defer语句会照常执行)
.NumGoroutine:返回正在执行和排队的任务总数
.GOOS:目标操作系统
1、Gosched

暂停当前goroutine,使其他goroutine先行运算。只是暂停,不是挂起,当时间片轮转到该协程时,Gosched()后面的操作将自动恢复

#未使用Gosched的代码
package main

import (
    "fmt"
)
func main() {
    go output("goroutine 2")
    output("goroutine 1")
}

func output(s string){
    for i:=0;i<3;i++{
        fmt.Println(s)
    }
}

#输出
#goroutine 1
#goroutine 1
#goroutine 1
#**结论:**还没等到子协程执行,主协程就已经执行完退出了,子协程将不再执行,所以打印的全部是主协程的数据。当然,实际上这个执行结果也是不确定的,只是大概率出现以上输出,因为主协程和子协程间并没有绝对的顺序关系
#使用Gosched的代码
package main

import (
    "fmt"
    "runtime"
)
func main() {
    go output("goroutine 2")
    runtime.Gosched()
    output("goroutine 1")
}
func output(s string){
    for i:=0;i<3;i++{
        fmt.Println(s)
    }
}
#输出:
#goroutine 2
#goroutine 2
#goroutine 2
#goroutine 1
#goroutine 1
#goroutine 1
#**结论:**在打印goroutine 1之前,主协程调用了runtime.Gosched()方法,暂停了主协程。子协程获得了调度,从而先行打印了goroutine 2。主协程不是一定要等其他协程执行完才会继续执行,而是一定时间。如果这个时间内其他协程没有执行完,那么主协程将继续执行,例如以下例子
#使用Gosched的代码,并故意延长子协程的执行时间,看主协程是否一直等待
package main

import (
    "fmt"
    "runtime"
    "time"
)
func main() {
    go func() {
        time.Sleep(5000)
        output("goroutine 2")
    }()
    runtime.Gosched()
    output("goroutine 1")
}

func output(s string) {
    for i := 0; i < 3; i++ {
        fmt.Println(s)
    }
}
#输出:
#goroutine 1
#goroutine 1
#goroutine 1

2、Goexit

立即终止当前协程,不会影响其它协程,且终止前会调用此协程声明的defer方法。由于Goexit不是panic,所以recover捕获的error会为nil

当main方法所在主协程调用Goexit时,Goexit不会return,所以主协程将继续等待子协程执行,当所有子协程执行完时,程序报错deadlock

package main

import (
    "fmt"
    "runtime"
    "time"
)

func main() {
    go func(){
        defer func(){
            fmt.Println("defer func executed!")
            fmt.Println("recovered error == ",recover())
        }()

        for i:=0;i<3;i++{
            if i==1{
                runtime.Goexit()
            }

            fmt.Println(i)
        }
    }()

    time.Sleep(2*time.Second)
}
#输出:
#0
#defer func executed!
#recovered error ==  <nil>

3、GOMAXPROCS(n int) int

设置可同时执行的逻辑Cpu数量,默认和硬件的线程数一致而不是核心数,可以通过调用GOMAXPROCS(-1)来获取当前逻辑Cpu数

最好在main函数之前设置它,GOMAXPROCS同时也是go的环境变量之一

当n<1:非法数字,方法不作修改

当n==1:单核心,多协程并发执行,并发只是看起来是同时执行的,实际上是同一时刻只有一个协程在跑,只是由于cpu的任务调度算法,让多个协程在效果上同时执行

当n>1:多核心,多协程并行执行,并行一定是并发,不同的核心同时地跑不同的协程

拷贝:https://blog.51cto.com/u_12732447/2432726

上一篇下一篇

猜你喜欢

热点阅读