只有 send:等待接收者
func first() int {
out := make(chan int)
go func() {
defer close(out)
for _, v := range []int{2, 4, 6} {
out <- v
}
}()
return <-out
}
defer close(out) 要等 goroutine 返回才會執行。它無法解除前面卡住的 send。
Go / 並行回顧
GOROUTINE · CHANNEL · CONTEXT
只需要第一個結果,卻啟動了會送出三個值的 producer。第一個值取到了,後面的 send 怎麼結束?
假設外層程式仍在運行。接收函式返回,不會替另一個 goroutine 執行 return。
兩個版本都取第一個值。修正版使用標準庫 context。
func first() int {
out := make(chan int)
go func() {
defer close(out)
for _, v := range []int{2, 4, 6} {
out <- v
}
}()
return <-out
}
defer close(out) 要等 goroutine 返回才會執行。它無法解除前面卡住的 send。
func first() int {
ctx, cancel := context.WithCancel(
context.Background(),
)
defer cancel()
out := make(chan int)
go func() {
defer close(out)
for _, v := range []int{2, 4, 6} {
select {
case out <- v:
case <-ctx.Done():
return
}
}
}()
return <-out
}
first 返回時呼叫 cancel。producer 可從 Done 分支返回,再關閉輸出。
若其他程式碼需要確認 producer 已退出,另用 WaitGroup 等待。若 send 與 Done 同時就緒,select 沒有「取消優先」保證。
go.dev/blog/pipelines — Stopping short、Explicit cancellation。pkg.go.dev/context — 取消通知與工作結束是兩回事。go.dev/ref/spec — 傳送的阻塞條件、就緒分支選擇及關閉行為。