Go語言探索 - 12(結(jié)局)

Go語言基礎(chǔ)系列博客用到的所有示例代碼

上一篇文章文章主要學(xué)習(xí)了Go語言中的接口、反射以及錯誤和異常處理。本篇文章主要學(xué)習(xí)Go語言的協(xié)程,當(dāng)然也是GO語言基礎(chǔ)的最后一篇。

goroutine:

goroutine是Go并行設(shè)計(jì)的核心,也是這門語言的精髓體現(xiàn)。goroutine這個關(guān)鍵字就是協(xié)程,但是它比線程更小。說起線程,大家可能都不陌生。線程,是程序執(zhí)行的最小單元。一個標(biāo)準(zhǔn)的線程由線程ID,當(dāng)前指令指針,寄存器集合和堆棧組成。另外,線程是進(jìn)程中的一個實(shí)體,是被系統(tǒng)獨(dú)立調(diào)度和分派的基本單位,線程自己不擁有系統(tǒng)資源,只擁有一點(diǎn)兒在運(yùn)行中必不可少的資源,但它可與同屬一個進(jìn)程的其它線程共享進(jìn)程所擁有的全部資源。

現(xiàn)在Go語言運(yùn)用協(xié)程這一比線程更小的執(zhí)行單元,十幾個goroutine可能體現(xiàn)在底層就是五六個線程,Go語言內(nèi)部幫你實(shí)現(xiàn)了這些goroutine之間的內(nèi)存共享。執(zhí)行g(shù)oroutine只需極少的棧內(nèi)存(大概是4~5KB),當(dāng)然會根據(jù)相應(yīng)的數(shù)據(jù)伸縮。也正因?yàn)槿绱耍赏瑫r運(yùn)行成千上萬個并發(fā)任務(wù)。goroutine比thread更易用、更高效、更輕便。

goroutine是通過Go的runtime管理的一個線程管理器。goroutine的作用就是一個普通的函數(shù)。以下是協(xié)程的寫法以及結(jié)果測試:

測試 - 1


測試 - 2


測試 - 3

理論上來說:多個goroutine運(yùn)行在同一個進(jìn)程里面,共享內(nèi)存數(shù)據(jù),不過設(shè)計(jì)上我們要遵循:不要通過共享來通信,而要通過通信來共享。goroutine運(yùn)行在相同的地址空間,因此訪問共享內(nèi)存必須做好同步。那么goroutine之間如何進(jìn)行數(shù)據(jù)的通信呢,Go提供了一個很好的通信機(jī)制:channel。

channel是Go中的一個核心類型,你可以把它看成一個管道,通過它并發(fā)核心單元就可以發(fā)送或者接收數(shù)據(jù)進(jìn)行通訊。

首先,channel必須先創(chuàng)建再使用,另外它的操作符是箭頭 <-

Channel類型的定義格式(有三種寫法)如下:

ChannelType = ( "chan" | "chan" "<-" | "<-" "chan" ) 數(shù)據(jù)類型

其中,這里的 <- 代表的是channel方向。如果沒有指定方向,那么Channel就是雙向,這樣就意味可以接收數(shù)據(jù),也可以發(fā)送數(shù)據(jù)。

(前面說了可以把channel看成一個管道,既然是管道那么就有流向)。也就是下面三種寫法:

chan T? ? ? ? ? // 可以接收和發(fā)送類型為 T 的數(shù)據(jù)

chan<- float64? // 只可以用來發(fā)送 float64 類型的數(shù)據(jù)

<-chan int? ? ? // 只可以用來接收 int 類型的數(shù)據(jù)

另外:

<-總是優(yōu)先和最左邊的類型結(jié)合。以下是幾種組合寫法:

chan<- chan int? ? // 等價 chan<- (chan int)

chan<- <-chan int? // 等價 chan<- (<-chan int)

<-chan <-chan int? // 等價 <-chan (<-chan int)

容量(capacity):

使用make也可以初始化Channel,并且可以設(shè)置channel的容量:

這里的容量可以這樣理解,就是channel可以存儲多少個元素,指定channel的緩沖大小、另外一個nil channel不會通信。

寫法:

ch := make(chan type, value)

當(dāng) value = 0 時,也就說明channel 是無緩沖阻塞讀寫的;

當(dāng) value > 0 時,channel 有緩沖、是非阻塞的,直到寫滿 value 個元素才阻塞寫入。例如:

容量

以上代碼不變,當(dāng)我們把容量設(shè)置為1,就會出現(xiàn)如下問題:

容量不足

Range和Close

range,這個關(guān)鍵字可以像操作slice或者map一樣,去操作緩存類型的channel;

close,這個關(guān)鍵字主要是用來關(guān)閉channel。關(guān)閉channel之后就無法再發(fā)送任何數(shù)據(jù)。


rang

上面的代碼都是只有一個channel的情況,那么如果存在多個channel的時候,我們該如何操作呢?

Go里面提供了一個關(guān)鍵字select,通過select可以監(jiān)聽channel上的數(shù)據(jù)流動。

它類似switch,但是只是用來處理通訊(communication)操作。它的case可以是send語句(發(fā)送),也可以是receive語句(接收),亦或者default。

default就是當(dāng)監(jiān)聽的channel都沒有準(zhǔn)備好的時候,默認(rèn)執(zhí)行

select默認(rèn)是阻塞的,只有當(dāng)監(jiān)聽的channel中有發(fā)送或接收可以進(jìn)行時才會運(yùn)行,當(dāng)多個channel都準(zhǔn)備好的時候,select是隨機(jī)的選擇一個執(zhí)行的。

代碼如下:

func main() {

c := make(chan int)

quit := make(chan int)

go func() {

for i := 0; i < 3; i++ {

fmt.Println("<-c == ",<-c)

}

quit <- 0

}()

testSelect(c, quit)

}

func testSelect(c, quit chan int) {

x, y := 1, 1

for {

select {

case c <- x:

x, y = y, x + y

fmt.Println("x == ",x)

fmt.Println("y+x == ",y+x)

case <- quit:

fmt.Println("quit")

return

}

}

}

超時處理:timeout

select有很重要的一個應(yīng)用就是超時處理。如果select中沒有case需要處理,select語句就會一直阻塞著。

這時候我們可能就需要一個超時操作,用來處理超時以避免整個程序進(jìn)入阻塞。Go語言的超時處理是使用的timeout關(guān)鍵字

以下是復(fù)現(xiàn)超時的例子,我分了兩種情況:

下面是第二種,復(fù)現(xiàn)超時的情景:

復(fù)現(xiàn)超時

下面是收集了一些runtime包中關(guān)于處理goroutine的幾個函數(shù):

A: Goexit 這個函數(shù)的意思指:退出當(dāng)前執(zhí)行的goroutine,但是defer函數(shù)還會繼續(xù)調(diào)用

B: Gosched 這個函數(shù)的意思指:讓出當(dāng)前goroutine的執(zhí)行權(quán)限,調(diào)度器安排其他等待的任務(wù)運(yùn)行,并在下次某個時候從該位置恢復(fù)執(zhí)行。

C: NumCPU 這個函數(shù)的意思指:返回 CPU 核數(shù)量

D: NumGoroutine 這個函數(shù)的意思指:返回正在執(zhí)行和排隊(duì)的任務(wù)總數(shù)

E: GOMAXPROCS 這個函數(shù)的意思指:用來設(shè)置可以并行計(jì)算的CPU核數(shù)的最大值,并返回之前的值。


結(jié)語:

關(guān)于Go語言的基礎(chǔ)內(nèi)容,基本上就寫完了。也算是這一階段的學(xué)習(xí)筆記與總結(jié)。

GoLang在學(xué)習(xí)的過程中,個人最深刻的體會就是對內(nèi)存的超嚴(yán)格控制管理、語法簡潔精悍、更小更精準(zhǔn)的協(xié)程執(zhí)行單元、函數(shù)多返回值等等特點(diǎn)。

雖然網(wǎng)上對這么語言褒貶不一,但還是希望這門語言可以發(fā)展的越來越好。

如果這篇文章對您有開發(fā)or學(xué)習(xí)上的些許幫助,希望各位看官留下寶貴的star,謝謝。

Ps:著作權(quán)歸作者所有,轉(zhuǎn)載請注明作者, 商業(yè)轉(zhuǎn)載請聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請注明出處(開頭或結(jié)尾請?zhí)砑愚D(zhuǎn)載出處,添加原文url地址),文章請勿濫用,也希望大家尊重筆者的勞動成果

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

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

  • Go語言并發(fā)模型 Go 語言中使用了CSP模型來進(jìn)行線程通信,準(zhǔn)確說,是輕量級線程goroutine之間的通信。C...
    副班長國偉閱讀 2,197評論 0 2
  • Chapter 8 Goroutines and Channels Go enable two styles of...
    SongLiang閱讀 1,733評論 0 3
  • 由淺入深剖析 go channel channel 是 golang 中最核心的 feature 之一,因此理解 ...
    不智魚閱讀 60,178評論 4 83
  • Goroutine是Go里的一種輕量級線程——協(xié)程。相對線程,協(xié)程的優(yōu)勢就在于它非常輕量級,進(jìn)行上下文切換的代價非...
    witchiman閱讀 5,143評論 0 9
  • 玫瑰 “少爺,這玫瑰開的更好了!”一個仆人拿著,灑水壺仔細(xì)地照料這一大片的玫瑰花,很是喜悅。 “嗯?!鄙倌攴鴷?,...
    奉柘閱讀 521評論 0 1

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