講講go中runtime包中三個(gè)方法Gosched、Goexit、GOMAXPROCS

go 中runtime 類似 Java 和 .NET 語(yǔ)言所用到的虛擬機(jī),它負(fù)責(zé)管理包括內(nèi)存分配、垃圾回收、棧處理、goroutine、channel、切片(slice)、map 和反射(reflection)等等。

runtime 調(diào)度器是個(gè)非常有用的東西,關(guān)于 runtime 包幾個(gè)方法:

.Gosched:讓當(dāng)前線程讓出 cpu 以讓其它線程運(yùn)行,它不會(huì)掛起當(dāng)前線程,因此當(dāng)前線程未來(lái)會(huì)繼續(xù)執(zhí)行
.NumCPU:返回當(dāng)前系統(tǒng)的 CPU 核數(shù)量
.GOMAXPROCS:設(shè)置最大的可同時(shí)使用的 CPU 核數(shù)
.Goexit:退出當(dāng)前 goroutine(但是defer語(yǔ)句會(huì)照常執(zhí)行)
.NumGoroutine:返回正在執(zhí)行和排隊(duì)的任務(wù)總數(shù)
.GOOS:目標(biāo)操作系統(tǒng)
1、Gosched

暫停當(dāng)前goroutine,使其他goroutine先行運(yùn)算。只是暫停,不是掛起,當(dāng)時(shí)間片輪轉(zhuǎn)到該協(xié)程時(shí),Gosched()后面的操作將自動(dòng)恢復(fù)

#未使用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
#**結(jié)論:**還沒(méi)等到子協(xié)程執(zhí)行,主協(xié)程就已經(jīng)執(zhí)行完退出了,子協(xié)程將不再執(zhí)行,所以打印的全部是主協(xié)程的數(shù)據(jù)。當(dāng)然,實(shí)際上這個(gè)執(zhí)行結(jié)果也是不確定的,只是大概率出現(xiàn)以上輸出,因?yàn)橹鲄f(xié)程和子協(xié)程間并沒(méi)有絕對(duì)的順序關(guān)系
#使用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
#**結(jié)論:**在打印goroutine 1之前,主協(xié)程調(diào)用了runtime.Gosched()方法,暫停了主協(xié)程。子協(xié)程獲得了調(diào)度,從而先行打印了goroutine 2。主協(xié)程不是一定要等其他協(xié)程執(zhí)行完才會(huì)繼續(xù)執(zhí)行,而是一定時(shí)間。如果這個(gè)時(shí)間內(nèi)其他協(xié)程沒(méi)有執(zhí)行完,那么主協(xié)程將繼續(xù)執(zhí)行,例如以下例子
#使用Gosched的代碼,并故意延長(zhǎng)子協(xié)程的執(zhí)行時(shí)間,看主協(xié)程是否一直等待
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

立即終止當(dāng)前協(xié)程,不會(huì)影響其它協(xié)程,且終止前會(huì)調(diào)用此協(xié)程聲明的defer方法。由于Goexit不是panic,所以recover捕獲的error會(huì)為nil

當(dāng)main方法所在主協(xié)程調(diào)用Goexit時(shí),Goexit不會(huì)return,所以主協(xié)程將繼續(xù)等待子協(xié)程執(zhí)行,當(dāng)所有子協(xié)程執(zhí)行完時(shí),程序報(bào)錯(cuò)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

設(shè)置可同時(shí)執(zhí)行的邏輯Cpu數(shù)量,默認(rèn)和硬件的線程數(shù)一致而不是核心數(shù),可以通過(guò)調(diào)用GOMAXPROCS(-1)來(lái)獲取當(dāng)前邏輯Cpu數(shù)

最好在main函數(shù)之前設(shè)置它,GOMAXPROCS同時(shí)也是go的環(huán)境變量之一

當(dāng)n<1:非法數(shù)字,方法不作修改

當(dāng)n==1:?jiǎn)魏诵?,多協(xié)程并發(fā)執(zhí)行,并發(fā)只是看起來(lái)是同時(shí)執(zhí)行的,實(shí)際上是同一時(shí)刻只有一個(gè)協(xié)程在跑,只是由于cpu的任務(wù)調(diào)度算法,讓多個(gè)協(xié)程在效果上同時(shí)執(zhí)行

當(dāng)n>1:多核心,多協(xié)程并行執(zhí)行,并行一定是并發(fā),不同的核心同時(shí)地跑不同的協(xié)程

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

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容