上下文被超时取消但计算没有中止?
Context cancelled by timeout but computation is not aborted?
试图了解 go 上下文取消将如何中止后续代码的执行
实验详情:
- main func 的上下文在
2sec
后超时
- main func 在一个单独的 go-routine 中调用另一个 func
sum
- 它为 test-运行-1 和 4sec
休眠 1sec
for test-运行-2
- 让 main 睡眠
3sec
让 spun 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
}
测试用例 1 的响应:1 秒的睡眠总和函数:
2021/04/12 01:06:58 print from sum fn: 11
2021/04/12 01:06:58 return from go routine: 11
测试用例 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秒后context已经超时取消,为什么还在diff go-routine中执行sum func并打印print from sum fn: 1
?
来自文档:Canceling this context releases resources associated with it.
我的假设是所有计算将在 2 秒后立即中止,包括 spun go-routine
让我知道如何正确执行此操作,在此先感谢
正如@AndySchweig 所指出的,context
表示取消事件,但不强制执行取消。任何潜在的阻塞 goroutine 都会在检测到取消后尽力尝试 cancel/clean-up。
要更新您的 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 例程对上下文一无所知。
试图了解 go 上下文取消将如何中止后续代码的执行
实验详情:
- main func 的上下文在
2sec
后超时
- main func 在一个单独的 go-routine 中调用另一个 func
sum
- 它为 test-运行-1 和4sec
休眠1sec
for test-运行-2 - 让 main 睡眠
3sec
让 spun 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
}
测试用例 1 的响应:1 秒的睡眠总和函数:
2021/04/12 01:06:58 print from sum fn: 11
2021/04/12 01:06:58 return from go routine: 11
测试用例 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秒后context已经超时取消,为什么还在diff go-routine中执行sum func并打印print from sum fn: 1
?
来自文档:Canceling this context releases resources associated with it.
我的假设是所有计算将在 2 秒后立即中止,包括 spun go-routine
让我知道如何正确执行此操作,在此先感谢
正如@AndySchweig 所指出的,context
表示取消事件,但不强制执行取消。任何潜在的阻塞 goroutine 都会在检测到取消后尽力尝试 cancel/clean-up。
要更新您的 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 例程对上下文一无所知。