go基础第三篇:context
1、带取消的context
context.WithCancel(parent Context) (ctx Context, cancel CancelFunc)
传入一个父context,返回一个可以手动取消的子context及其取消函数。
我们可以手动调用cancel()函数来取消子context,当cancel()被调用后,或者父context被取消后,子context的Done channel会close,通过<-ctx.Done()方式监听子context的所有goroutine都会收到通知(得到一个空对象)。cancel一个context会释放关联的资源,所以context应该尽快cancel,如果不需要手动cancel的话,要用defer cancel()。
常见用法:主协程调用WithCancel方法,生成一个子context及取消函数。在子协程中使用for循环,用select多路选择从子context的Done方法返回的channel中取数据。在主协程中调用取消函数,当子协程从子context的Done方法返回的channel中取到数据后,就退出子协程。
2、带超时的context
context.WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunction)
context.WithDeadline(parent Context, timeout time.time) (Context, CancelFunction)
withTimeout底层是调用withDeadline。
传入一个父context和一个时间,返回一个到点自动取消的子context及其取消函数。
func main() { ctx, cancelF := context.WithTimeout(context.Background(), time.Second*3) defer func() { fmt.Println("context cancel") cancelF() }() go task(ctx) time.Sleep(time.Second * 10) } func doSomething(ch chan int) { time.Sleep(time.Second * 2) ch <- 0 } func task(ctx context.Context) { ch := make(chan int, 0) go doSomething(ch) select { case a := <-ch: fmt.Println("a=", a) case b := <-ctx.Done(): fmt.Println("超时", b) } }
3、带值的context
context.WithValue(parent Context, key, val interface{}) Context
传入一个父context和一个键值对,返回一个子context。可以在子协程中调用子context的Value()方法根据键获取值。
func main() { ctx := context.WithValue(context.Background(), "requestId", "7a9f3b87-2efe-4a58-9be0-d1a5a8a488f1") go task(ctx) time.Sleep(time.Second * 3) } func task(ctx context.Context) { requestId := ctx.Value("requestId") fmt.Println(requestId) fmt.Println(reflect.TypeOf(requestId)) }
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步