golang context 超时自动取消方法

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()消息,超时才能退出。

posted @ 2020-04-30 16:36  JaneySJ  阅读(8108)  评论(2编辑  收藏  举报