如下代码,到了超时时间后,main中已经监测到超时了,但是真正处理任务的代码还是在继续执行,这个起不到超时的真正作用,如何能够在超时后停止处理任务handleTask()?
```golang
package main
import (
"context"
"fmt"
"time"
)
//处理任务
func handleTask(ctx context.Context, ch chan bool, taskId int) {
for i := 0; i < 5; i++ {
time.Sleep(time.Second)
fmt.Println(fmt.Sprintf("处理任务 %d:%d, %v", taskId, i, time.Now()))
}
ch <- true
}
func main() {
//任务总数
taskNum := 2
//超时时间
timeoutSecond := time.Second * 2
ctx, cancleFun := context.WithTimeout(context.Background(), timeoutSecond)
ch := make(chan bool)
for i := 1; i <= taskNum; i++ {
go handleTask(ctx, ch, i)
}
allCount := 0
ForControl:
for allCount < taskNum {
select {
case <-ch:
allCount++
if allCount == taskNum {
break ForControl
close(ch)
}
case <-ctx.Done():
cancleFun()
fmt.Println("超时", ctx.Err())
break ForControl
}
}
time.Sleep(timeoutSecond * 2)
}
```
第一点 我感觉你超时的用法有点错误了。
cancleFun()这个函数在你的代码中是无效的。这个函数的作用只有通知ctx.Done。而你使用WithTimeout倒计时结束后也会通知ctx.Done().
第二点 超时结束不是程序就马上结束。你需要在代码层面进行处理才能结束,实际上他只有一个通知ctx.Done一个功能。
如果你想让你的goroutine在超时的时候结束,也很简单,主函数中相似的逻辑 实现在 goroutine中就可以了。
```
//处理任务
func handleTask(ctx context.Context, ch chan bool, taskId int) {
for i := 0; i < 5; i++ {
select {
case <-ctx.Done():
return
default:
time.Sleep(time.Second)
fmt.Println(fmt.Sprintf("处理任务 %d:%d, %v", taskId, i, time.Now()))
}
}
ch <- true
}
```
#1
更多评论
第一点认同。
第二点 感觉不太好实现,生产环境下handleTask()是没有for 的,都是串行的处理逻辑,没有合适的位置来监听ctx.Done()。
#2
那我觉得你原来的代码也没什么问题,反正计时结束,程序返回了超时,至于是否有goroutine在运行我觉得其实不是非常需要关心。我觉得超时的主要目的是为了防止长时间等待造成程序无返回。
#3