WithTimeout 超时自动取消方法,当执行一个go 协程时,超时自动取消协程
package main
import (
"fmt"
"time"
"context"
)
func main() {
ctx, _ := context.WithTimeout(context.Background(), 5 * time.Second)
fmt.Println("start at ", time.Now().Format("2006-01-02 15:04:05"))
go func() {
defer func() {
fmt.Println("goroutine exit ", time.Now().Format("2006-01-02 15:04:05"))
}()
for {
select {
case <-ctx.Done(): // 因为ctx带超时参数,当时间期限到了之后就会走到这里退出协程
fmt.Println("Done. ", time.Now().Format("2006-01-02 15:04:05"))
return
default: // 协程循环执行for,当ctx.Done()无信号时总是走到Default分支
fmt.Println("case default ", time.Now().Format("2006-01-02 15:04:05"))
time.Sleep(time.Second)
}
}
}()
time.Sleep(20 * time.Second) // 主程序用sleep阻塞住
fmt.Println("stop at ", time.Now().Format("2006-01-02 15:04:05"))
}
在使用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()消息,超时才能退出。