Context context

Context.Context is the Go language used to set the deadline, synchronization signal, request related value structure. Context is closely related to Goroutine and is unique to Go, a concept we rarely see in other programming languages.

Context.Context is a Go interface introduced into the standard library in version 1.7. This interface defines four methods to be implemented, including:

  • Deadline – returnscontext.ContextThe time of cancellation, the deadline for completion of the work;
  • Done – Returns oneChanneltheChannelCloses multiple times after the current work has completed or the context has been cancelledDoneMethod will return the sameChannel;
  • Err – returnscontext.ContextEnd of reason, it will only be inDoneMethod correspondingChanneL Returns a non-empty value when closed; ifcontext.ContextCancelled, returnsCanceledError; If the context.ContextTimeout, returnsDeadlineExceededError;
  • From the Value –context.ContextFor the same context, multiple callsValueAnd pass in the sameKeyReturns the same result. This method can be used to pass the requested specific data;
type Context interface {
	Deadline() (deadline time.Time, ok bool)
	Done() <-chan struct{}
	Err() error
	Value(key interface{}) interface{}
}
Copy the code

The context.Background, context.TODO, context.WithDeadline, and context.WithValue functions provided in the context package return private structures that implement the interface.

Signal synchronization

func main() {
	ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
	defer cancel()

	go handle(ctx, 500*time.Millisecond)
	select {
	case <-ctx.Done():
		fmt.Println("main", ctx.Err())
	}
}

func handle(ctx context.Context, duration time.Duration) {
	select {
	case <-ctx.Done():
		fmt.Println("handle", ctx.Err())
	case <-time.After(duration):
		fmt.Println("process request with", duration)
	}
}
Go

Copy the code

Default context

The most common methods used in context packages are context.Background and context.TODO. Both methods return pre-initialized private variables Background and TODO, which are reused in the same Go program

var (
    background = new(emptyCtx)
    todo       = new(emptyCtx)
)
Copy the code

Background is usually used in the main function as the root node of any context.

Todo is usually used when you don’t know what context to pass. For example, if you’re calling a function that needs to pass the context argument, and you don’t have another context to pass, you can pass todo. This often happens during refactoring, when you add a Context parameter to some function, but don’t know what to pass, use todo to “take a place”, and end up with another Context.

cancel

The context.WithCancel function can derive a new subcontext from context. context and return the function used to cancel the context. Once we execute the cancellation function returned, the current context and its subcontexts are cancelled, and all Goroutines receive the cancellation signal synchronously.

func WithCancel(parent Context) (ctx Context, cancel CancelFunc) {
	c := newCancelCtx(parent)
	propagateCancel(parent, &c)
	return &c, func() { c.cancel(true, Canceled) }
}
Copy the code
func propagateCancel(parent Context, Child canceler) {done: = parent.done () if done == nil {return // the parent context does not trigger the cancellation signal} select {case <-done: Return default:} if p, ok := parentCancelCtx(parent); parentCancelCtx(parent); parentCancelCtx(parent); ok { p.mu.Lock() if p.err ! = nil { child.cancel(false, p.err) } else { p.children[child] = struct{}{} } p.mu.Unlock() } else { go func() { select { case <-parent.Done(): child.cancel(false, parent.Err()) case <-child.Done(): } }() } }Copy the code
  1. When parent.done () == nil, the current function returns when parent does not trigger cancel;
  2. When the child’s inheritance chain contains a context that can be cancelled, it determines whether the parent has triggered the cancellation signal. If already cancelled, the child is cancelled immediately; If not cancelled, the child is added to the parent’s children list, waiting for the parent to release the cancel signal.
  3. When the parent context is a developer-defined type that implements the context.context interface and returns a non-empty pipe in the Done() method; Run a new Goroutine that listens on both parent.Done() and child.done () channels. Cancels the subcontext by calling child.cancel when parent.Done() is closed;

Value passed

Context. WithValue in the context package can create a child context from the parent context, passing the value to a child context of type context.valuectx

func WithValue(parent Context, key, val interface{}) Context { if key == nil { panic("nil key") } if ! reflectlite.TypeOf(key).Comparable() { panic("key is not comparable") } return &valueCtx{parent, key, val} }Copy the code
type valueCtx struct {
	Context
	key, val interface{}
}

func (c *valueCtx) Value(key interface{}) interface{} {
	if c.key == key {
		return c.val
	}
	return c.Context.Value(key)
}
Copy the code

If you have any questions or want to know more, you can follow my official accountJim the Superhero, left a message on the official account, I saw the first reply.