了解 Golang Context

golang context

Posted by alovn on June 24, 2019

golang在context包下提供了一个Context,它可以用来在多个goroutine之间传递信号

1
2
3
4
5
6
7
8
9
10
type Context interface {

    Deadline() (deadline time.Time, ok bool)

    Done() <-chan struct{}

    Err() error

    Value(key interface{}) interface{}
}

Done方法在context被取消或者工作完成时返回一个close掉的channel,如果context无法被取消,则可能返回一个nil

Deadline 返回context到达指定时间被取消的时间

Background

backGround 不可被取消,没有deadLine

WithCancel

WithCancel返回一个继承的Context,这个Context在父Context的Done被关闭时关闭自己的Done通道,或者在自己被Cancel的时候关闭自己的Done。 WithCancel同时还返回一个取消函数cancel,这个cancel用于取消当前的Context。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
func someHandler() {
    c := context.Background()
    ctx, cancel := context.WithCancel(c)
    go doStuff(ctx)

    //10秒后取消doStuff
    time.Sleep(5 * time.Second)
    cancel()
}

//每1秒work一下,同时会判断ctx是否被取消了,如果是就退出
func doStuff(ctx context.Context) {
    for {
        time.Sleep(1 * time.Second)
        select {
        case <-ctx.Done():
            fmt.Println("done")
            return
        default:
            fmt.Println("work")
        }
    }
}

func main() {
    someHandler()
}

withTimeout

设置超时时间,类似withCancel,只是多了一个超时时间,调用cancel或者达到超时时间context都会被取消

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
func someHandler() {
    c := context.Background()
    ctx, cancel := context.WithTimeout(c, time.Second*3)
    go doStuff(ctx)

    //10秒后取消doStuff
    time.Sleep(5 * time.Second)
    cancel()

}

//每1秒work一下,同时会判断ctx是否被取消了,如果是就退出
func doStuff(ctx context.Context) {
    for {
        time.Sleep(1 * time.Second)
        select {
        case <-ctx.Done():
            fmt.Println("done")
            return
        default:
            fmt.Println("work")
        }
    }
}

func main() {
    someHandler()
}

withDeadline

withDeadline等价于withTimeout,只是讲超时时间改为截止时间

withValue

withValue返回了一个key与value相关联的context

1
2
3
4
5
6
7
8
9
10
11
12
13
14
func someHandler() {
    c := context.Background()
    ctx := context.WithValue(c, "a", "b")
    go doStuff(ctx)
    time.Sleep(time.Second)
}

func doStuff(ctx context.Context) {
    fmt.Println(ctx.Value("a"))
}

func main() {
    someHandler()
}