如何解决在 Go 中处理长期操作时等待上下文完成通道取消
在这种情况下:
- 第一个 go 例程正在处理一个长期运行的操作并阻塞直到它完成
- 第二个 goroutine 可以随时取消整个任务
- 当整个任务被取消时,第一个 goroutine 应该只是退出操作并立即返回。
这是我的解决方案。它有效,但感觉不优雅或 Go 风格。
你能纠正我或告诉我更好的解决方案吗?
var (
workTimeCost = 6 * time.Second
cancelTimeout = 5 * time.Second
)
ctx,cancel := context.WithCancel(context.Background())
var (
data int
readCh = make(chan struct{})
)
go func() {
log.Println("blocked to read data")
// fake long i/o operations
time.Sleep(workTimeCost)
data = 10
log.Println("done read data")
readCh <- struct{}{}
}()
// fake cancel is called from the other routine (it's actually not caused by timeout)
time.AfterFunc(cancelTimeout,cancel)
select {
case <-ctx.Done():
log.Println("cancelled")
return
case <-readCh:
break
}
log.Println("got final data",data)
解决方法
Close readCh
表示长时间运行的 goroutine 已完成。与发送值相比,关闭通道有两个好处:
- close 可以方便地使用 defer 调用
- close 在上下文被取消的情况下不会阻塞。如果在 goroutine 完成之前取消上下文,问题中的代码会泄漏 goroutine。
这是更新后的代码:
var (
workTimeCost = 6 * time.Second
cancelTimeout = 5 * time.Second
)
ctx,cancel := context.WithCancel(context.Background())
var (
data int
readCh = make(chan struct{})
)
go func() {
defer close(readCh)
log.Println("blocked to read data")
// fake long i/o operations
time.Sleep(workTimeCost)
data = 10
log.Println("done read data")
}()
// fake cancel is called from the other routine (it's actually not caused by timeout)
time.AfterFunc(cancelTimeout,cancel)
select {
case <-ctx.Done():
log.Println("cancelled")
return
case <-readCh:
break
}
log.Println("got final data",data)
如果不需要区分长时间运行的goroutine的完成和取消,从goroutine调用cancel函数。
var (
workTimeCost = 6 * time.Second
cancelTimeout = 5 * time.Second
)
ctx,cancel := context.WithCancel(context.Background())
var data int
go func() {
defer cancel()
log.Println("blocked to read data")
// fake long i/o operations
time.Sleep(workTimeCost)
data = 10
log.Println("done read data")
}()
// fake cancel is called from the other routine (it's actually not caused by timeout)
time.AfterFunc(cancelTimeout,cancel)
<-ctx.Done()
log.Println("got final data",data)
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。