注意:我用谷歌搜索了这个主题,并阅读了我能找到的几乎所有内容,但仍然无法获得正确/合理/生产就绪的答案。
基本上所有答案都差不多,就像这个:how to stop a groutine , 都采用相同的模式,无一异常(exception):真正的工作是 fmt.Println(1)
打印一些东西,或者只是// Do other stuff
,
但如果将实际工作保留在 for select default case branch
, 然后它将被执行多次,用于打印一些东西它很好,但显然它还没有为实际工作做好准备。
我能想到的唯一有效方法是将真正的工作放在一个案例分支上,然后向该案例发送仅一个信号以通知它开始,就像这里:playground ,但只是觉得苦恼,同样使用这种方法,它是否会产生一些潜在的问题?
添加代码片段以准确显示我想要实现的目标:https://play.golang.org/p/7xjjiW7XdoQ ,我想实现当客户端关闭连接时,立即终止我的处理程序,释放资源,并无条件退出。
最佳答案
您不想使用 for select
循环,而是要在多个地方检查取消信号。但是为了不阻塞,您仍然必须使用 select
(默认大小写为空),这有点尴尬。我使用的是 context.Context 而不是“普通取消 channel ”,但想法是一样的:
func doWork(ctx context.Context) {
fmt.Println("Doing some work 1")
time.Sleep(time.Second * 5)
// check is the task cancelled
select {
case <-ctx.Done():
fmt.Println("cancelled at checkpoint 1")
return
default:
}
fmt.Println("Doing some work 2")
time.Sleep(time.Second * 5)
// check is the task cancelled
select {
case <-ctx.Done():
fmt.Println("cancelled at checkpoint 2")
return
default:
}
fmt.Println("Doing some work 3")
time.Sleep(time.Second * 5)
}
func main() {
var wg sync.WaitGroup
wg.Add(1)
ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
defer cancel()
go func() {
doWork(ctx)
wg.Done()
}()
wg.Wait()
fmt.Println("done")
}
关于go - 如何使用 channel 通知 goroutine 正确退出,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50489557/