標籤:通過 原因 str 設定 通訊 時間 sof sleep 非同步
並發Concurrency
很多人都是衝著 Go 大肆宣揚的高並發而忍不住躍躍欲試,但其實從源碼的解析來看,goroutine 只是由官方實現的超級“線程池”而已。不過話說回來,每個執行個體 4~5KB的棧記憶體佔用和由於實現機制而大幅減少的建立和銷毀開銷,是製造 Go 號稱的高並發的根本原因。另外,goroutine 的簡單易用,也在語言層面上給予了開發人員巨大的遍曆。
高並發當中一定要注意:並發可不是並行。
並發主要由切換時間片來實現“同時”運行,而並行則是直接利用多核實現多線程的運行,但 Go 可以設定使用核心數,以發揮多核電腦的處理能力。
goroutine 奉行通過通訊來共用記憶體,而不是共用記憶體來通訊。Go 語言主要是通過 Channe 技術通訊來實現記憶體的共用的,因為 channel 是一個通道,Go 是通過通道來通訊進行記憶體資料的共用。
讓我們先來看一個最簡單的 goroutine 案例:
package mainimport ( "fmt" "time")func main() { //啟用一個goroutine go GoRun() //這裡加一個休眠是因為主線程已啟動就執行完畢消亡來,子線程還來不及執行 time.Sleep(2 * time.Second)}func GoRun() { fmt.Println("Go Go Go!!!")}
運行結果:
Go Go Go!!!
Channel
1. Channel 是 goroutine 溝通的橋樑,大都是阻塞同步的
2. 它是通過 make 建立,close 關閉
3. Channel 是參考型別
4. 可以使用 for range 來迭代,不斷操作 channel
5. 可以設定單向 或 雙向通道
6. 可以設定緩衝大小,在未被填滿前不會發生阻塞,即它是非同步
那麼針對上溯代碼我們不使用休眠,而使用 Channel 來實現我們想要的效果:
package mainimport ( "fmt")func main() { //聲明建立一個通道,儲存類型為bool型 c := make(chan bool) //啟用一個goroutine,使用的是匿名方法方式 go func() { fmt.Println("Go Go Go!!!") c <- true //向 channel 中存入一個值 }() //當程式執行完畢之後再從通道中取出剛才賦的值 <- c /** 主線程啟動了一個匿名子線程後就執行到了:<-c , 到達這裡主線程就被阻塞了。只有當子線程向通道放入值後主線程阻塞才會被釋放 其實這個就是完成了訊息的發送 */}
上溯代碼可以修改為使用 for range 來進行訊息的發送:
package mainimport ( "fmt")func main() { //聲明建立一個通道,儲存類型為bool型,這裡設定的channel就是雙向通道,既可以存也可以取 c := make(chan bool) //啟用一個goroutine,使用的是匿名方法方式 go func() { fmt.Println("Go Go Go!!!") c <- true //向 channel 中存入一個值 close(c) //切記如果使用for range來進行取值的時候需要在某個地方進行關閉,否則會發生死結 }() //從通道中迴圈取出剛才賦的值 for v := range c { fmt.Println(v) }}
從以上代碼可以看出,一般使用的 Channel 都是雙向通道的,即:既可以取又可以存。那單向通道一般用於什麼情境下呢?
單向通道又分為兩種,一種是只能讀取,一種是只能存放,一般用於參數類型傳遞使用。例如有個方法返回一個Channel類型,一般要求操作只能從這裡取,那麼此時它的用途就是只能存放類型,如果此時你不小心存資料,此時會發生panic 導致程式奔潰發生異常。那麼讀取類型的Channel同理。這樣做其實也是為了程式的安全性與健壯性,防止一些誤操作。
這裡還有一個知識點,就是有緩衝的channel 和 無緩衝的channel的區別?
make(chan bool, 1) 表示帶有一個緩衝大小的緩衝channel;make(chan bool) 表示一個無緩衝的channel
無緩衝channel是阻塞的即同步的,而有緩衝channel是非同步。
怎麼說?比如
c1:=make(chan int) 無緩衝
c2:=make(chan int,1) 有緩衝
c1<-1
無緩衝的 不僅僅是 向 c1 通道放 1 而是 一直要有別的攜程 <-c1 接手了 這個參數,那麼 c1<-1 才會繼續下去,要不然就一直阻塞著
而 c2<-1 則不會阻塞,因為緩衝大小是1 只有當 放第二個值的時候 第一個還沒被人拿走,這時候才會阻塞。
打個比喻
無緩衝的 就是一個送信人去你家門口送信 ,你不在家 他不走,你一定要接下信,他才會走。
無緩衝保證信能到你手上
有緩衝的 就是一個送信人去你家仍到你家的信箱 轉身就走 ,除非你的信箱滿了 他必須等信箱空下來。
有緩衝的 保證 信能進你家的郵箱
GO_11:GO語言基礎之並發concurrency