英文:
Strange in Go start groutine in loop with cancel context
问题
我的情况:处理器有三次重试,每次重试花费一秒钟,处理器不能超时,所以我使用CancelContext
来控制它。
我的处理器函数:
func process(ctx context.Context, ch chan<- int) {
fmt.Println("process execute")
select {
case <-ctx.Done():
fmt.Println("process receive done signal, return")
return
default:
fmt.Println("execute default")
time.Sleep(4 * time.Second) // 处理一些事情...
ch <- 1
return
}
}
情况1
func main(){
ctx, cancel := context.WithCancel(context.Background()) // 处理超时
for i := 0; i < 3; i++ { // 重试3次
flag := make(chan int, 1)
go process(ctx, flag)
select {
case <-flag:
fmt.Println("main receive task done")
case <-time.After(time.Second * 3):
cancel()
fmt.Println("main receive timeout")
}
}
}
输出:
process execute
execute default
main receive timeout
process execute
process receive done signal, return
main receive timeout
process execute
process receive done signal, return
main receive timeout
**问题:**奇怪的是,为什么execute default
只在第一次循环中打印?
情况2
我在循环中定义了上下文:
func main(){
for i := 0; i < 3; i++ {
ctx, cancel := context.WithCancel(context.Background()) // 在循环中定义
flag := make(chan int, 1)
go process(ctx, flag)
select {
case <-flag:
fmt.Println("main receive task done")
case <-time.After(time.Second * 3):
cancel()
fmt.Println("main receive timeout")
}
}
}
输出:
process execute
execute default
main receive timeout
process execute
execute default
main receive timeout
process execute
execute default
main receive timeout
**问题:**为什么process
函数从未打印process receive done signal, return
,它没有接收到ctx.Done()
信号吗?
对不起,我的英语不好,非常感谢。
英文:
my situation: processor have three retry, and spend second peer retry, and processor cannot be timeout, so i use the CancelContext
to controll it.
my processor function:
func process(ctx context.Context, ch chan<- int) {
fmt.Println("process execute")
select {
case <-ctx.Done():
fmt.Println("process receive done signal, return")
return
default:
fmt.Println("execute default")
time.Sleep(4 * time.Second) // something handle...
ch <- 1
return
}
}
situation 1
func main(){
ctx, cancel := context.WithCancel(context.Background()) // handle timeout
for i := 0; i < 3; i++ { // retry 3
flag := make(chan int, 1)
go process(ctx, flag)
select {
case <-flag:
fmt.Println("main receive task done")
case <-time.After(time.Second * 3):
cancel()
fmt.Println("main receive timeout ")
}
}
}
output:
process execute
execute default
main receive timeout
process execute
process receive done signal, return
main receive timeout
process execute
process receive done signal, return
main receive timeout
question: somethine strange happend, why execute default
only print in first loop?
situation 2
i define context in loop:
func main(){
for i := 0; i < 3; i++ {
ctx, cancel := context.WithCancel(context.Background()) // define in loop
flag := make(chan int, 1)
go process(ctx, flag)
select {
case <-flag:
fmt.Println("main receive task done")
case <-time.After(time.Second * 3):
cancel()
fmt.Println("main receive timeout ")
}
}
}
output:
process execute
execute default
main receive timeout
process execute
execute default
main receive timeout
process execute
execute default
main receive timeout
question: why process function never print process receive done signal, return
, does it not receive the ctx.Done()
singal ?
sorry for my bad english, thank you very much
答案1
得分: 1
有些奇怪的事情发生了,为什么只有在第一个循环中执行默认的打印操作?
因为当你到达第二个和第三个进程时,你的共享上下文已经被取消了。
为什么 process 函数从未打印出 process receive done signal 和 return,它没有接收到 ctx.Done() 信号吗?
因为当你调用 process 函数时,它执行了 select 语句,由于上下文尚未完成,select 语句进入了默认情况,并且不会返回。
英文:
> somethine strange happend, why execute default only print in first
> loop?
Because when you reach the second and the third process your shared context is already canceled.
> why process function never print process receive done signal, return,
> does it not receive the ctx.Done() singal ?
Because when you call process you execute select and since your context is not done - select goes to the default case and doesn't come back.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论