context
1、子协程修改context,用指针,如下,否则修改失败
ctx := context.Background()
go func(ctx *context.Context) {
*ctx = context.WithValue(*ctx, "test", 2)
}(&ctx) //传指针
time.Sleep(time.Second)
fmt.Println(ctx.Value("test"))
2、cancel后,自身和子ctx都cancel,父ctx不cancel
如下例,ctx1是ctx2之父,ctx2是ctx3之父
ctx1 := context.Background()
ctx2, cancel := context.WithCancel(ctx1)
ctx3 := context.WithValue(ctx2, "test", "test string")
cancel()
go func(ctx context.Context) {
if ctx.Err() != nil {
fmt.Println("ctx1 closed")
} else {
fmt.Println("ctx1 not closed")
}
}(ctx1)
go func(ctx context.Context) {
if ctx.Err() != nil {
fmt.Println("ctx2 closed")
} else {
fmt.Println("ctx2 not closed")
}
}(ctx2)
go func(ctx context.Context) {
if ctx.Err() != nil {
fmt.Println("ctx3 closed")
} else {
fmt.Println("ctx3 not closed")
}
}(ctx3)
time.Sleep(time.Second * 2)
// Unordered output:
// ctx1 not closed
// ctx2 closed
// ctx3 closed
cancel源码:
func (c *cancelCtx) cancel(removeFromParent bool, err error) {
if err == nil {
panic("context: internal error: missing cancel error")
}
c.mu.Lock()
if c.err != nil {
c.mu.Unlock()
return // already canceled
}
c.err = err
if c.done == nil {
c.done = closedchan
} else {
close(c.done)
}
for child := range c.children {
// NOTE: acquiring the child's lock while holding parent's lock.
child.cancel(false, err)
}
c.children = nil
c.mu.Unlock()
if removeFromParent {
removeChild(c.Context, c)
}
}