如何解决上下文因超时取消但计算未中止?
试图了解 go 上下文取消将如何中止后续代码的执行
实验细节:
- main func 的上下文在
2sec
中超时 - main func 在单独的 go-routine 中调用另一个 func
sum
- 它在1sec
为 test-run-1 和4sec
为 test-run-2 睡眠 - 让主线程休眠
3sec
以让旋转的 go-routine 完成执行
package main
import (
"context"
"fmt"
"log"
"time"
)
func main() {
c := context.Background()
childCtx,cancel := context.WithTimeout(c,2*time.Second)
defer cancel()
ch := make(chan int,1)
go sum(5,6,ch)
var msg string
select {
case <-childCtx.Done():
msg = "return from ctx done channel"
case res := <-ch:
msg = fmt.Sprintf("return from go routine: %v",res)
}
log.Print(msg)
time.Sleep(3 * time.Second) //sleeping here to test if go-routine is still running
}
func sum(x int,y int,c chan<- int) {
time.Sleep(1 * time.Second)
//testcase-1: sleep - 1s
//testcase-2: sleep - 4s
result := x + y
log.Printf("print from sum fn: %v",result)
c <- result
}
testcase-1 的响应:1 秒的睡眠总和函数:
2021/04/12 01:06:58 print from sum fn: 11
2021/04/12 01:06:58 return from go routine: 11
testcase-2 的响应:4 秒的睡眠总和函数:
2021/04/12 01:08:25 return from ctx done channel
2021/04/12 01:08:27 print from sum fn: 11
在 testcase-2 中,当 sum func 休眠 4 秒时,上下文已经在 2 秒后被超时取消,为什么它仍然在 diff go-routine 中执行 sum func 并打印 print from sum fn: 1
?
来自文档:Canceling this context releases resources associated with it.
我的假设是所有计算将在 2 秒后立即中止,包括旋转的 go-routine
让我知道如何正确地做到这一点,提前致谢
解决方法
正如@AndySchweig 所指出的,context
表示取消事件,但不强制取消。在检测到取消后,任何潜在的阻塞 goroutine 都应尽最大努力尝试取消/清理。
要更新您的 sum
函数以支持取消,您可以尝试:
// add context parameter as the first argument
// add a return error - to indicate any errors (i.e. function was interrupted due to cancelation)
func sum(ctx context.Context,x int,y int,c chan<- int) (err error) {
wait := 1 * time.Second // testcase-1
//wait := 4 * time.Second // testcase-2
// any blocking called - even sleeps - should be interruptible
select {
case <-time.After(wait):
case <-ctx.Done():
err = ctx.Err()
return
}
result := x + y
log.Printf("print from sum fn: %v",result)
select {
case c <- result:
case <-ctx.Done(): // check for ctx cancelation here - as no one may be listening on result channel
err = ctx.Err()
}
return
}
,
上下文不会中止 go 例程。在您的情况下,如果上下文时间已过,您只是不打印 go 例程的结果。 go 例程对上下文一无所知。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。