golang context使用

context

context是go并发模式,用户处理goroutines和其父亲之间逻辑。比如接受一个用户的请求后,针对这个请求可能需要开启多个并发的goroutine,如何把这些goroutine和这个client进行关联?就是通过context,如果用户取消请求,所有的goroutine应该能感知,并自动结束。同时可以将共用的变量存储在context之中,供不同的goroutine使用。

从一个程序说起

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
func main() {
out := make(chan int)
go func() {
i := 0
for i < 3 {
out <- i
fmt.Println("Send ", i)
i = i + 1
}
close(out)
}()
fmt.Println(<-out)
time.Sleep(1 * time.Minute)
}

退出的时候,sub goroutine还没结束,存在资源泄露的情况。

使用context协调sub goroutine

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
func test() {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
out := make(chan int)
go func() {
i := 0
for i < 3 {
select {
case out <- i:
fmt.Println("Send ", i)
i = i + 1
case <-ctx.Done():
fmt.Println("Done") fmt.Println(ctx.Err())
return
}
}
close(out)
}()
fmt.Println(<-out)
fmt.Println("cancal being call")
}
func main() {
test()
time.Sleep(5 * time.Second)
}

使用timeout自动执行cancel

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
29
30
func test() {
ctx, _ := context.WithTimeout(context.Background(), 5*time.Second)
out := make(chan int)
go func() {
i := 0
for i < 3 {
select {
case out <- i:
fmt.Println("Send ", i)
i = i + 1
case <-ctx.Done():
fmt.Println("Done")
fmt.Println(ctx.Err())
return
}
}
close(out)
}()
fmt.Println(<-out)
for i := 1; i <= 10; {
time.Sleep(1 * time.Second)
fmt.Println("wait for ", i, " sec ")
i = i + 1
}
}
func main() {
test()
}

相关链接

  1. context blog
  2. example code

本文标题:golang context使用

文章作者:Louis

发布时间:2017年11月07日 - 13:11

最后更新:2018年04月11日 - 14:04

原始链接:/2017/11/07/go-context/

许可协议: Louis-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。