channel用於goroutine之間的通訊golang
若是不用channel,使用共享全局變量的方式,須要加鎖安全
// synchornized 同步 // golang中的 sync包中有互斥鎖 var lock sync.Mutex // mutex 互斥 lock.Lock() // 上鎖 // 多個goroutine同時對相同的數據進行修改 lock.Unlock() // 解鎖
使用同步鎖併發效率會很低數據結構
channel主要用於goroutine通訊和解決主線程等待goroutine執行結束再退出的問題併發
chan string
,只能保存string數據var variableName chan dataType
函數
var c1 chan int var c2 chan bool var c3 chan map[int]string
channel 是引用類型,必須初始化後才能使用線程
var c1 chan int c1 = make(chan int, 4) // 使用make函數初始化chan int, 4是容量 // 初識化以後容量不可動態變化,channel不會自動擴容,寫入數據時不能超過容量,不然會deadlock // fatal error: all goroutines are asleep - deadlock! c1 <- 666 // 寫入數據 num := <- c1 // 取出數據, 每取一個數據,channel長度減一 // 不使用goroutine的狀況下 // 當數據所有取出是再對channel取數據會報 deadlock
內置函數close(channel) 能夠關閉channel,不能再添加數據,可是能夠讀取數據code
channel能夠用for range方式遍歷協程
可是必須是已關閉的channel隊列
for range遍歷一個未關閉的channel會出現deadlock字符串
c1 := make(chan int, 10) for i:=0; i<10; i++ { c1 <- i } close(c1) for v := range c1 { fmt.Println(v) }
對於一個已關閉的channel讀取數據時,若是數據已所有取出,取值狀態返回false而不會報錯
func main() { c1 := make(chan int, 2) c1 := make(chan int, 2) c1 <- 1 c1 <- 2 c2 <- 1 c2 <- 2 close(c1) <- c1 // 取出值 丟棄不用 1 <- c1 // 2 v, ok := <-c1 // 數據已取完 fmt.Println(v,ok) // 0 false <- c2 // 1 <- c2 // 2 v, ok := <-c2 // 數據已取完 程序到這裏會出錯 deadlock fmt.Println(v,ok) }
對於已關閉的管道,能夠在取完數據時結束等待goroutine執行
for { _, ok := <- exitChan bool if !ok { break } }
未關閉的channel須要取出指定個數的值以後結束等待goroutine執行
channel默認是既能夠讀又能夠寫的
能夠聲明爲只讀或只寫
var c1 <- chan int // 只讀 var c2 chan <- int // 只寫
通常channel不會聲明爲只讀和只寫,而是在聲明函數形參的時候使用
var c1 chan string func sendData(c chan <- string) {...} func readData(c <- chan string) {...} // c1是默承認讀可寫的channel // 當c1做爲參數傳給 sendData時 在 sendData 函數中只容許對管道進行寫操做 // 當c1做爲參數傳給 readData時 在 readData 函數中只容許對管道進行讀操做
goroutine中使用recover函數解決協程中出現的panic ,不影響主線程的執行
defer func() { if err = recover(); err != nil { ...dosomething } }
select用於解決從管道中取數據的阻塞問題
不使用select,在遍歷未關閉的管道時會deadlock
然而,不少狀況下管道都是未關閉的,由於很差肯定何時關
用select來遍歷未關閉管道,不會deaklock
func main() { c1 := make(chan int, 10) c2 := make(chan string, 5) for i := 0; i < 10; i++ { rand.Seed(time.Now().UnixNano()) c1 <- rand.Intn(100) } c2 <- "commerce" c2 <- "corresponding" c2 <- "oblige" c2 <- "decline" c2 <- "praise" label1: for { select { case v := <-c1: fmt.Println(v) case v := <-c2: fmt.Println(v) default: fmt.Println("兩個管道都沒數據了吧") break label1 } } fmt.Println("adhere") }