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 () { 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 () { 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 () { test() }
|
相关链接
- context blog
- example code
近期评论