假设发生以下情况:
- 我们有下面的
Consumer
函数,在一个goroutine中运行。 - 另一个goroutine是在
intChan
通道上发送整数,没有任何延迟。换句话说,在for循环的每次迭代中,都有一个值准备在intChan
上接收。 - 启动
Consumer
goroutine的goroutine取消了传入Consumer
的context。因此,ctx.Done()
信道也具有准备好被接收的值。
问题:
- 在这种情况下,select语句的两个case都准备好运行了。
- 根据tour of Go,
select
将随机选择一个案例,因为两者都准备好运行。 - 如何保证
select
不会继续选择<- intChan
shell ?如果<- ctx.Done()
和<- ctx.Done()
在for循环的每次迭代中都准备好了,我们怎么知道<- ctx.Done()
最终会被选中?
func Consumer(ctx context.Context, intChan chan int) {
for {
select {
case <-ctx.Done():
return
case i := <-intChan:
foo(i)
}
}
}
字符串
在下面的程序中,我尝试使用Consumer
函数。在这个程序的几次运行中,Consumer
和Producer
goroutine似乎总是终止。
为什么我们不以永远不执行<-ctx.Done()
案例的运行结束呢?
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:
}
}
}
型
1条答案
按热度按时间sh7euo9m1#
没有任何保证。保证终止的最简单方法是在select语句外使用
ctx.Err()
检查错误。将错误返回给传递上下文的代码也很常见。我会这样写消费者函数:字符串