- 为啥需要context, 可以参考这个文章
https://www.flysnow.org/2017/05/12/go-in-action-go-context.html
package main
import (
"fmt"
"context"
"time"
)
func main() {
// context.Background 返回一个空 Context -- 根节点。。
ctx, cancel := context.WithCancel(context.Background())
// context.WithCancel 创建了一个可取消的子 Context
go func(ctx context.Context) {
for {
select {
// 接受是否可取消的channel
case <-ctx.Done():
fmt.Println("exit ...")
return
default:
fmt.Println("going ...")
time.Sleep(2 * time.Second)
}
}
}(ctx)
time.Sleep(10 * time.Second)
fmt.Println("notify ...")
// 创建时返回的 cancel ... 直接执行即可取消。
cancel()
// 等待检查是否退出
time.Sleep(5 * time.Second)
}
/**
going ...
going ...
going ...
going ...
going ...
notify ...
exit ...
*/
- context包能干什么
type Context interface {
// 设置超时
Deadline() (deadline time.Time, ok bool)
// 用来确定是否取消了
Done() <-chan struct{}
// 获取ctx的错误 可以是 超时 DeadlineExecced 也可以是 canceled
Err() error
// 绑定一些值.
Value(key interface{}) interface{}
}
内置的两个 emptyCtx, 即根Context
- background
- todo
// 创建一个可以取消的
func WithCancel(parent Context) (ctx Context, cancel CancelFunc)
// 创建一个有结束时间的 -- time.AfterFunc 到某个时间之后结束
func WithDeadline(parent Context, deadline time.Time) (Context, CancelFunc)
// 从当前开始经过多长时间之后结束
func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc)
// 绑定key value到Context中
func WithValue(parent Context, key, val interface{}) Context
// 大概就是这些东西了呀
1. 不要把Context放在结构体中,要以参数的方式传递
2. 以Context作为参数的函数方法,应该把Context作为第一个参数,放在第一位。
3. 给一个函数方法传递Context的时候,不要传递nil,如果不知道传递什么,就使用context.TODO
4. Context的Value相关方法应该传递必须的数据,不要什么数据都使用这个传递
5. Context是线程安全的,可以放心的在多个goroutine中传递
这个文章说了context的坏话
https://faiface.github.io/post/context-should-go-away-go2/
网友评论