14 Go并發(fā)編程(一):協(xié)程 —— Go并發(fā)的基本運(yùn)行單元

Go協(xié)程

1.什么是goroutine?

Go在語(yǔ)言級(jí)別原生支持并發(fā)操作,這在現(xiàn)代眾多基于線程并發(fā)的其他語(yǔ)言來(lái)看是比較鶴立雞群的。在Go中最基本的并發(fā)任務(wù)單元是一種稱為goroutine的東西,我們把它叫做協(xié)程或go程,其開(kāi)一個(gè)并發(fā)任務(wù)簡(jiǎn)單到令人發(fā)指,只需go關(guān)鍵字,就能讓一個(gè)函數(shù)成為并發(fā)任務(wù)。

示例:

//啟動(dòng)go程并發(fā)
func BaseGoroutine01() {
    //開(kāi)辟一條協(xié)程
    go func() {
        fmt.Println("這里是獨(dú)立開(kāi)辟的協(xié)程打印的?。?!")
    }()

    //開(kāi)辟十條協(xié)程
    for i := 1; i <= 10; i++ {
        go func(num int) {
            fmt.Println("這里由協(xié)程", num, "打?。。?!")
        }(i)
    }

    //把一個(gè)命名函數(shù)作為協(xié)程運(yùn)行
    go goroutineFunc()
    fmt.Println("這里由父協(xié)程打?。。?!")

    //父協(xié)程必須留有足夠長(zhǎng)時(shí)間讓子協(xié)程運(yùn)行完,暫時(shí)用睡眠
    time.Sleep(time.Second)

}

func goroutineFunc() {
    for i := 1; i <= 10; i++ {
        fmt.Println(i)
    }
}

go的協(xié)程有如下幾個(gè)特點(diǎn):

  • Go的協(xié)程是一個(gè)輕量級(jí)的線程,多個(gè)協(xié)程可能運(yùn)行在一個(gè)或者多個(gè)線程上;
  • Go的協(xié)程是非搶占式多任務(wù)處理,需要由協(xié)程主動(dòng)交出控制權(quán),這與其他搶占型的線程并發(fā)方式不同,這種非搶占式設(shè)計(jì)減少了許多cpu調(diào)度切換的開(kāi)銷(xiāo);
  • Go的協(xié)程是一個(gè)虛擬機(jī)層面的多任務(wù)處理,它基于Go的并發(fā)調(diào)度器,其調(diào)度是go運(yùn)行時(shí)自動(dòng)管理的,對(duì)用戶不可見(jiàn),用戶只需管理業(yè)務(wù)層面的并發(fā)即可。
  • Go中所有的調(diào)用棧都是一個(gè)協(xié)程,main()函數(shù)就是主協(xié)程,如無(wú)開(kāi)辟其他協(xié)程所有任務(wù)都在主協(xié)程運(yùn)行。

然而,go的協(xié)程雖然號(hào)稱能開(kāi)百萬(wàn)級(jí),但也不是無(wú)節(jié)制的是亂開(kāi)線程,其也是有一些規(guī)則甚至是陷阱的,下面我們來(lái)了解一些go的協(xié)程特性及用法:

2.go協(xié)程特性:主死從隨

主協(xié)程沒(méi)有阻塞的執(zhí)行完,程序結(jié)束,子協(xié)程無(wú)論有無(wú)執(zhí)行完都會(huì)結(jié)束。


func main() {
    go func() {
        for i := 1; i <= 10; i++ {
            fmt.Println("子協(xié)程輸出", i)
            time.Sleep(time.Second)
        }
    }()

    //主協(xié)程只存活5s
    for i := 1; i <= 5; i++ {
        fmt.Println("主協(xié)程輸出", i)
        time.Sleep(time.Second)
    }

}
3. go協(xié)程特性:出讓協(xié)程資源

go的協(xié)程是非搶占式的,占有cpu資源的協(xié)程如無(wú)主動(dòng)讓出,其他協(xié)程只能等待:使用runtime.Gosched()進(jìn)行控制

func BaseGoroutine03() {

    for i := 1; i <= 10; i++ {
        go func(n int) {

            //出讓奇數(shù)協(xié)程資源
            if n%2 == 1 {
                //這里使用runtime包控制協(xié)程的cpu資源讓出
                runtime.Gosched()
            }

            for j := 1; j <= 5; j++ {
                fmt.Println("第", n, "協(xié)程:第", j, "次打印")
            }

        }(i)
    }

    time.Sleep(time.Second * 3)

}
4.go協(xié)程特性:設(shè)置并查看可用cpu核心數(shù)

在如今的多核時(shí)代,go程序能夠充分利用cpu核心數(shù),其runtime包中提供可設(shè)置查看可用cpu核心數(shù)的函數(shù):runtime.GOMAXPROCS()

func BaseGoroutine04() {

    numCPU := runtime.NumCPU()
    fmt.Println("CPU邏輯核心數(shù):", numCPU)

    //GOMAXPROCS設(shè)置可同時(shí)執(zhí)行的最大CPU數(shù),并返回先前的設(shè)置
    prevNum := runtime.GOMAXPROCS(2)
    fmt.Println("設(shè)置CPU核心數(shù)為2,設(shè)置前為", prevNum)

}
5.go協(xié)程特性:協(xié)程退出

使用runtime.Goexit()可讓協(xié)程退出,父協(xié)程和子協(xié)程各自退出的后果不同,子協(xié)程退出后提前執(zhí)行defer,非善終(協(xié)程不會(huì)正常返回),父協(xié)程退出會(huì)令子協(xié)程失去牽制,主從皆死程序崩潰。

//子協(xié)程退出
func BaseGoroutine05() {
    go func() {
        for i := 1; i <= 5; i++ {
            if i == 3 {
                fmt.Println("子協(xié)程打印到3,協(xié)程退出!")
                runtime.Goexit()
            }
            fmt.Println("子協(xié)程輸出", i)
            time.Sleep(time.Second)
        }
    }()

    for i := 1; i <= 10; i++ {
        fmt.Println("主協(xié)程打印", i)
        time.Sleep(time.Second)
    }
}
6.go協(xié)程特性:協(xié)程間按調(diào)度器隊(duì)列執(zhí)行,公平使用資源

非搶占式的并發(fā)模型不會(huì)主動(dòng)占有cpu資源,開(kāi)啟協(xié)程后其會(huì)在調(diào)度器中的協(xié)程隊(duì)列排隊(duì),除非別人出讓資源,否則按隊(duì)列執(zhí)行,關(guān)于Go的并發(fā)調(diào)度模型會(huì)另開(kāi)專題討論。

//協(xié)程簡(jiǎn)公平使用資源
func BaseGoroutine06() {
    go func() {
        for i := 1; i <= 10; i++ {
            fmt.Println("協(xié)程1:自己排隊(duì)!")
            time.Sleep(time.Nanosecond)
        }
    }()

    go func() {
        for i := 1; i <= 10; i++ {
            fmt.Println("協(xié)程2:自己排隊(duì)!")
            time.Sleep(time.Nanosecond)
        }
    }()

    time.Sleep(time.Second)

}
最后編輯于
?著作權(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)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

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