go 有提供關閉 channel 的函數: close(ch)
在讀取時可以多一個變數取得 channel 的狀態
例如:
msg, ok := <- ch1
if ok {
println(msg)
}
這樣可以避免去讀取一個已關閉的 channel
但奇怪的是,go 卻未提供判斷 channel 是否已關閉的功能
例如類似這樣的函數:
isClosed(ch1)
基於常久以來的習慣,總是會想在寫入前先做判斷
一直到目前的 1.5rc1 版,都還沒有這樣的函數
不過還有是其它方式可做到類似效果
只是不用 close(ch)
直接將這個 channel 設為 nil
package main
import (
"fmt"
"math/rand"
"time"
)
const funcNum, gCountMax int = 20, 360
func main() {
rand.Seed(time.Now().UTC().UnixNano())
ch1, ch2 := make(chan string), make(chan string)
for idx := 0; idx < funcNum; idx++ {
go func(fid int) {
fCount := 0
for {
if ch1 != nil {
ch1 <- fmt.Sprintf(" [%v]: %v ", fid, fCount)
fCount++
if fCount > 18 {
ch1 = nil
}
time.Sleep(time.Millisecond * time.Duration(rand.Intn(30)*5))
} else {
return
}
}
}(idx)
}
gCount := 0
rCount := 0
go func() {
defer func() { ch2 <- "Done!" }()
for {
select {
case msg, ok := <-ch1:
if ok {
print(msg)
rCount++
}
gCount++
if gCount >= gCountMax {
ch1 = nil
}
default:
if ch1 == nil {
return
}
}
}
}()
msg := <-ch2
fmt.Printf("\n%v, %s\n", rCount, msg)
}
if ch1 != nil {
ch1 <- fmt.Sprintf(" [%v]: %v ", fid, fCount)
.....
這邊在寫入 channel 前先判斷是否為 nil
當然,就不要再用 close() 關閉 channel