context
大约 2 分钟
context
一、常用API
WithValue 查找顺序 多层级 context 值覆盖
主要弄清楚 WithValue\WithTimeout\WithDeadline\WithCancel 如何实现 子上下文和父上下文如何相互通讯的
- 跟上下文被子协程A添加了timeout会影响到同样适用跟上下文的协程B吗
不会
- background和todo有什么区别
两个都是 emptyCtx int 都实现了接口 context.Context
- context源码角度是一个什么样的结构
context.Context是一个interface 也就是一个待实现的接口
WithCancel() 和 WithTimeout() 可以通知多个goroutine, 如何实现的
ctx的key为name的value被子协程更改后,在主协程会变更吗
不会变
- WithTimeout和WithCancel等本质上做了什么事情
context包有结构体 cancelCtx timerCtx valueCtx
本质上每一次WithTimeout都是重新创建一个结构体,并且把当前的接口体赋到新结构体的属性变量之中
所以结构体中存储parentContext
以context.WithCancel为例
如何在 parent.Done 的时候子 children.Done 呢
本质上是起一个协程并且阻塞在 case <-parent.Done()
然后在阻塞通过后执行 children.Done
当执行 WithCancel 的时候,其实就是重新创建一个 cancelCtx 并且调用 propagateCancel 方法
监听父级别上下文的信号,保证父级上下文关闭后,子上下文也发出cancel信号
- c.Value 的访问
每次 WithValue 都会封装一次 valueCtx,然后把值和key存储到新的 valueCtx 之中
c.Value 的访问,是对当前的上下文的value访问,如果找不到那么查找父级上下文,找不到继续如何迭代查找
- WithTimeout如何实现的
源码是通过注册 time.AfterFunc 调用 ctx.cancel 函数执行的
为什么说context是线程安全的,如何实现的
context读取value会有什么问题(时间复杂度讲一下)嵌套很多层会逐个访问O(N)
contextl.Value的并发安全通过sync.Mutex实现
Context.WithTimeout的使用
解释一下WithTimeout的cancel是否要直接defer
package main
import (
"context"
"fmt"
"time"
)
func ccc() context.Context {
ctx, cancel := context.WithTimeout(context.Background(), 4*time.Second)
// defer会在ccc执行完成以后立即调用
// 从而导致直接触发<-ctx.Done
// 无法等到timeOut后触发
defer cancel()
return ctx
}
func main() {
ctx := ccc()
select {
case <-ctx.Done():
fmt.Println("Context done.")
case <-time.After(3 * time.Second):
fmt.Println("Timeout after 3 seconds.")
}
}