有時你會與來自系統不同部分的通道交互。與管道不同的是,當你使用的代碼通過done通道取消操作時,你無法對通道的行為方式做出判斷。也就是說,你不知道正在執行讀取操作的goroutine現在是什么狀態。出于這個原因,正如我們在“防止Goroutine泄漏”中所闡述的那樣,需要用select語句來封裝我們的讀取操作和done通道。可以簡單的寫成這樣:
```
for val := range myChan {
// 對 val 進行處理
}
```
展開后可以寫成這樣:
```
loop:
for {
select {
case <-done:
break loop
case maybeVal, ok := <-myChan:
if ok == false {
return // or maybe break from for
}
// Do something with val
}
}
```
這樣做可以快速退出嵌套循環。繼續使用goroutines編寫更清晰的并發代碼,而不是過早優化的主題,我們可以用一個goroutine來解決這個問題。 我們封裝了細節,以便其他人調用更方便:
```
orDone := func(done, c <-chan interface{}) <-chan interface{} {
valStream := make(chan interface{})
go func() {
defer close(valStream)
for {
select {
case <-done:
return
case v, ok := <-c:
if ok == false {
return
}
select {
case valStream <- v:
case <-done:
}
}
}
}()
return valStream
}
```
這樣做允許我們回到簡單的循環方式:
```
for val := range orDone(done, myChan) {
// Do something with val
}
```
你可能會在代碼中發現需要使用一系列select語句的循環代碼,但我會鼓勵你先嘗試提高可讀性,并避免過早優化。
* * * * *
學識淺薄,錯誤在所難免。我是長風,歡迎來Golang中國的群(211938256)就本書提出修改意見。
- 前序
- 誰適合讀這本書
- 章節導讀
- 在線資源
- 第一章 并發編程介紹
- 摩爾定律,可伸縮網絡和我們所處的困境
- 為什么并發編程如此困難
- 數據競爭
- 原子性
- 內存訪問同步
- 死鎖,活鎖和鎖的饑餓問題
- 死鎖
- 活鎖
- 饑餓
- 并發安全性
- 優雅的面對復雜性
- 第二章 代碼建模:序列化交互處理
- 并發與并行
- 什么是CSP
- CSP在Go中的衍生物
- Go的并發哲學
- 第三章 Go的并發構建模塊
- Goroutines
- sync包
- WaitGroup
- Mutex和RWMutex
- Cond
- Once
- Pool
- Channels
- select語句
- GOMAXPROCS
- 結論
- 第四章 Go的并發編程范式
- 訪問范圍約束
- fo-select循環
- 防止Goroutine泄漏
- or-channel
- 錯誤處理
- 管道
- 構建管道的最佳實踐
- 便利的生成器
- 扇入扇出
- or-done-channel
- tee-channel
- bridge-channel
- 隊列
- context包
- 小結
- 第五章 可伸縮并發設計
- 錯誤傳遞
- 超時和取消
- 心跳
- 請求并發復制處理
- 速率限制
- Goroutines異常行為修復
- 本章小結
- 第六章 Goroutines和Go運行時
- 任務調度