假设出现以下情况:
-
我们有下面的
Consumer
函数,运行在Goroutine中. -
另一个Goroutine正在毫无延迟地在
intChan
通道上发送整数.换句话说,在for循环的每一次迭代中,都有一个值准备在intChan
上接收. -
启动
Consumer
号大猩猩的大猩猩,取消了进入Consumer
号大猩猩的背景.因此,ctx.Done()
通道也有一个可供接收的值.
问题:
- 在这种情况下,SELECT语句的两种情况都可以运行.
- 根据tour of Go,
select
将随机挑选一个病例,因为两个都已经准备好运行. - 如何保证
select
个人不会一直 Select<- intChan
个 case ?如果这两个 case 在for循环的每个迭代中都准备好了,我们如何知道<- ctx.Done()
case 最终会被选中?
func Consumer(ctx context.Context, intChan chan int) {
for {
select {
case <-ctx.Done():
return
case i := <-intChan:
foo(i)
}
}
}
在下面的程序中,我try 使用了Consumer
函数.
在这个程序的几次运行中,Consumer
和Producer
个Goroutine似乎总是终止.
为什么我们不以运行<-ctx.Done()
个 case 的方式结束呢?
package main
import (
"context"
"fmt"
"sync"
"time"
)
func main() {
ctx, cancelFunc := context.WithCancel(context.Background())
var wg sync.WaitGroup
wg.Add(2) // add 2, because we spawn 2 goroutines
Producer(ctx, &wg)
fmt.Println(time.Now())
time.Sleep(time.Second * 5) // cancel the context after 5 seconds
cancelFunc()
fmt.Println("CANCELLED")
wg.Wait() // wait till both producer and consumer goroutines terminate
fmt.Println(time.Now())
}
func Producer(ctx context.Context, wg *sync.WaitGroup) {
intChan := make(chan int)
go Consumer(ctx, intChan, wg)
go func() {
defer wg.Done()
for {
select {
case <-ctx.Done():
return
case intChan <- 1:
}
}
}()
}
func Consumer(ctx context.Context, intChan chan int, wg *sync.WaitGroup) {
defer wg.Done()
for {
select {
case <-ctx.Done():
return
case _ = <-intChan:
}
}
}