Go經常利用goroutine中的infinit loop(無窮迴圈)去接收channel送來的訊息,而透過Context
離開goroutine無窮迴圈的方式如下。
呼叫context.WithCancel
取得cancel CancelFunc
,並在滿足離開條件時呼叫cancel()
。
在goroutine無窮迴圈中使用select敘述選擇接收不同channel的處理。設定一case為當ctx.Done()
因context的cancel()
被呼叫而回傳關閉的channel時去調用return
離開無窮迴圈。default case則執行離開迴圈前的一般邏輯。
至於exit
channel是用來阻塞main程序的goroutine,直到另一條執行無窮迴圈的goroutine離開前exit<true
傳入值才會解除<-exit
的阻塞繼續往下執行。
main.go
package main
import (
"context"
"fmt"
"time"
)
func main() {
fmt.Println("start")
ctx, cancel := context.WithCancel(context.Background()) // create cancel context
ch := make(chan int) // make an unbuffered 'ch' channel
go send(ch) // send values to 'ch' channel
exit := make(chan bool) // make an 'exit' channel. channel block begin
go func(ctx context.Context) {
for { // infinit loop
select {
case <-ctx.Done(): // when context's Done channel is closed by cancel()
fmt.Println("done")
exit <- true // send a value to 'exit' channel
return
default:
i := <-ch // receive values from 'ch' channel
fmt.Println(i)
if i == 3 {
cancel() // close context's Done channel
}
}
}
}(ctx) // pass cancel context as a goroutine func's parameter
<-exit // channel block end, receive value from 'exit' channel
close(exit) // close channel
fmt.Println("end")
}
func send(ch chan int) {
for i := 1; i < 5; i++ {
ch <- i
time.Sleep(1 * time.Second)
}
}
執行程式印出以下:
start
1
2
3
done
end
沒有留言:
張貼留言