WithTimeout 超时自动取消方法,当执行一个go 协程时,超时自动取消协程
package main
import (
"fmt"
"time"
"context"
)
var res int
// 模拟一个最小执行时间的阻塞函数
func inc(a int) int {
res = a + 1 // 虽然我只做了一次简单的 +1 的运算,
time.Sleep(10 * time.Second) // 但是由于我的机器指令集中没有这条指令,
// 所以在我执行了 1000000000 条机器指令, 续了 1s 之后, 我才终于得到结果。B)
return res
}
// 向外部提供的阻塞接口
// 计算 a + b, 注意 a, b 均不能为负
// 如果计算被中断, 则返回 -1
func Add(ctx context.Context, a, b int) int {
res = 0
go inc(res) //要是协程
for {
select {
case <-ctx.Done():
fmt.Println("ctx Done in a")
return -1
default:
}
}
for i := 0; i < b; i++ {
res = inc(res)//执行完才会走到select中
select {
case <-ctx.Done():
fmt.Println("ctx Done in b")
return -1
default:
}
}
return res
}
func main() {
// 使用开放的 API 计算 a+b
a := 1
b := 2
timeout := 1000 * time.Millisecond
ctx, cancel := context.WithTimeout(context.Background(), timeout)
defer cancel()
res := Add(ctx, 1, 2)
fmt.Printf("Compute: %d+%d, result: %d
", a, b, res)
}
在使用golang开发中,调用外部可执行程序通过exec包是我们常用的方式。如何控制超时请见如下代码:
func CmdWithTimeout(name string, arg ...string) ([]byte, error) {
//timeout 的值可以放在环境变量里
timeoutstr, err := strconv.Atoi(os.Getenv("cmd-timeout"))
if err != nil {
log.Errorf("fail to load netlink timeout: %v", err)
return nil, err
}
timeoutval := time.Duration(timeoutstr) * time.Millisecond
ctxt, cancel := context.WithTimeout(context.Background(), timeoutval)
defer cancel()
cmd := osexec.CommandContext(ctxt, name, arg...)
var ret []byte
ret, err = cmd.CombinedOutput()
return ret, err
}
需要搭配接收ctx.Done()消息,超时才能退出。