Context 派生:
ctx,_ := context.WithTimeout(context.Background(),(10 * time.Second))
源码分析:
// WithTimeout returns WithDeadline(parent,time.Now().Add(timeout)).
//
// Canceling this context releases resources associated with it,so code should
// call cancel as soon as the operations running in this Context complete:
//
// func slowOperationWithTimeout(ctx context.Context) (Result,error) {
// ctx,cancel := context.WithTimeout(ctx,100*time.Millisecond)
// defer cancel() // releases resources if slowOperation completes before timeout elapses
// return slowOperation(ctx)
// }
func WithTimeout(parent Context,timeout time.Duration) (Context,CancelFunc) {
return WithDeadline(parent,time.Now().Add(timeout))
}
func WithDeadline(parent Context,deadline time.Time) (Context,CancelFunc) {
if cur,ok := parent.Deadline(); ok && cur.Before(deadline) {
// 被派生的context设置了超时且当前时间小于超时时间
// The current deadline is already sooner than the new one.
return WithCancel(parent)
}
c := &timerCtx{
cancelCtx: newCancelCtx(parent),deadline: deadline,}
// check deadline passed
propagateCancel(parent,c)
d := time.Until(deadline)
if d <= 0 {
c.cancel(true,DeadlineExceeded) // deadline has already passed
return c,func() { c.cancel(true,Canceled) }
}
c.mu.Lock()
defer c.mu.Unlock()
if c.err == nil {
// timeout and cancel context
c.timer = time.AfterFunc(d,func() {
c.cancel(true,DeadlineExceeded)
})
}
return c,Canceled) }
}
func WithCancel(parent Context) (ctx Context,cancel CancelFunc) {
// 创建新的context
c := newCancelCtx(parent)
propagateCancel(parent,&c)
return &c,Canceled) }
}
func propagateCancel(parent Context,child canceler) {
if parent.Done() == nil {
return // parent is never canceled
}
// get partner cancel context
if p,ok := parentCancelCtx(parent); ok {
p.mu.Lock()
if p.err != nil {
// parent has already been canceled
child.cancel(false,p.err)
} else {
// build with map
if p.children == nil {
p.children = make(map[canceler]struct{})
}
p.children[child] = struct{}{}
}
p.mu.Unlock()
} else {
go func() {
select {
// if parent close,then child close()
case <-parent.Done():
child.cancel(false,parent.Err())
case <-child.Done():
}
}()
}
}
//判断parent是否为cancelCtx类型
func parentCancelCtx(parent Context) (*cancelCtx,bool) {
for {
switch c := parent.(type) {
case *cancelCtx:
return c,true
case *timerCtx:
return &c.cancelCtx,true
case *valueCtx:
parent = c.Context
default:
return nil,false
}
}
}
context 类型:
1. 可cancel的context:
// A cancelCtx can be canceled. When canceled,it also cancels any children
// that implement canceler.
type cancelCtx struct {
Context
done chan struct{} // closed by the first cancel call.
mu sync.Mutex
children map[canceler]struct{} // set to nil by the first cancel call
err error // set to non-nil by the first cancel call
}
// return channel !!!
func (c *cancelCtx) Done() <-chan struct{} {
return c.done
}
func (c *cancelCtx) Err() error {
c.mu.Lock()
defer c.mu.Unlock()
return c.err
}
func (c *cancelCtx) String() string {
return fmt.Sprintf("%v.WithCancel",c.Context)
}
// cancel closes c.done,cancels each of c's children,and,if
// removeFromParent is true,removes c from its parent's children.
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
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)
}
}
- 带着计时的可cancel的context(匿名cancel的context)
// A timerCtx carries a timer and a deadline. It embeds a cancelCtx to // implement Done and Err. It implements cancel by stopping its timer then // delegating to cancelCtx.cancel.
type timerCtx struct {
cancelCtx
timer *time.Timer // Under cancelCtx.mu.
deadline time.Time
}
func (c *timerCtx) Deadline() (deadline time.Time,ok bool) {
return c.deadline,true
}
func (c *timerCtx) String() string {
return fmt.Sprintf("%v.WithDeadline(%s [%s])",c.cancelCtx.Context,c.deadline,time.Until(c.deadline))
}
func (c *timerCtx) cancel(removeFromParent bool,err error) {
c.cancelCtx.cancel(false,err)
if removeFromParent {
// Remove this timerCtx from its parent cancelCtx's children.
removeChild(c.cancelCtx.Context,c)
}
c.mu.Lock()
if c.timer != nil {
c.timer.Stop()
c.timer = nil
}
c.mu.Unlock()
}
key-value pair
// A valueCtx carries a key-value pair. It implements Value for that key and
// delegates all other calls to the embedded Context.
type valueCtx struct {
Context
key,val interface{}
}
func (c *valueCtx) String() string {
return fmt.Sprintf("%v.WithValue(%#v,%#v)",c.Context,c.key,c.val)
}
func (c *valueCtx) Value(key interface{}) interface{} {
if c.key == key {
return c.val
}
return c.Context.Value(key)
}