This is a creation in Article, where the information may have evolved or changed.
Prospect
The context package troubled me for a long time, before watch ETCD the first use of the package, then did not understand the role of the package, only know can be used to close watch, and then by Daniel Spit Groove, decided to delve deeper.
Brief introduction
Golang in the creation of a new goroutine, does not return a similar C-language PID, all of us can not kill a certain goroutine from the outside, all I have to let it end, before we use Channel + Select way to solve this problem, However, some scenarios are cumbersome to implement, such as the need to satisfy certain constraints between the various goroutine that derive from a request, such as the expiration date, the abort routine tree, and the ability to pass the request global variables. So Google provides us with a solution to open up the context package. Using context to implement a contextual function convention requires passing in a context to the first of the incoming parameters of your method. A variable of type Context.
SOURCE Analysis
Context. Context interface
The core of the context package
the method in the context package is thread-safe and can be used by multiple goroutine with type context interface { //When the context is canceled or times out, Don E returns a closed channel done () <-chan struct{} //The reason that err represents being closed after the Do channel is closed err () Error / /If present, Deadline returns the time at which the context will be closed Deadline () (Deadline. Time, OK bool) //If present, value returns the value associated with key, there is no return nil value (key interface{}) interface{}}
We do not need to implement this interface manually, the context package has provided us with two, one is Background (), one is TODO (), both functions will return a context instance. Just the two instances returned are empty Context.
Main structure
The CANCELCTX structure inherits the Context and implements the Canceler method:
Both the *cancelctx and *timerctx implement the Canceler interface, and the type of implementation of the interface can be directly Canceledtype Canceler interface {cancel (removefromparent bool, E RR error) Done () <-chan struct{}} type cancelctx struct {Context do chan struct{}//Closed by the F Irst Cancel call. Mu sync. Mutex children Map[canceler]bool//set to nil by the first cancel call err Error//When it is cancel will put E The RR is set to non-Nil}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)}//core is off c.done//also set c.err = err, C.children = nil// Iterate through C.children, each child cancel//if Removefromparent is set, then C removes the Func (c *cancelctx) cancel from the children of its parent ( removefromparent bool, err error) {if Err = = Nil {Panic ("context:internal error:missing Cancel Error")} C.mu.lock () if c.err! = nil {c.mu.unlock () returnAlready 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)//From here you can see that the CANCELCTX context item is a concept similar to the parent}}
TIMERCTX Structure Inheritance Cancelctx
Type timerctx struct { cancelctx//package here in order to inherit the method from Cancelctx, Cancelctx.context is the Father node pointer to timer *time. Timer//Under CANCELCTX.MU. is a timer deadline time. TIME}
VALUECTX Structure Inheritance Cancelctx
Type valuectx struct { Context key, Val interface{}}
Main methods
Func Withcancel (Parent context) (CTX context, cancel Cancelfunc) Func Withdeadline (parent context, deadline time. Time) (context, Cancelfunc) func withtimeout (parent Context, timeout time. Duration) (context, Cancelfunc) func withvalue (parent Context, Key interface{}, Val interface{}) Context
Withcancel corresponds to Cancelctx, which returns a Cancelctx, and returns a Cancelfunc,cancelfunc is a function type defined in the context package: Type Cancelfunc func (). When calling this cancelfunc, close the corresponding C.done, that is, let his descendants goroutine exit.
Withdeadline and Withtimeout correspond to Timerctx, Withdeadline and withtimeout are similar, withdeadline is set specific deadline time, when arriving at Deadline, Descendants Goroutine exit, while Withtimeout is simply rude, return directly to Withdeadline (parent, time. Now (). ADD (timeout)).
Withvalue corresponds to Valuectx, Withvalue is set up in the context of a map, get this context and its descendants of the Goroutine can get the value of the map.
Detailed Context package source interpretation: Go Source code interpretation
Principles of Use
Packages that use Context need to follow the following guidelines to satisfy interface consistency and facilitate static analysis
Do not put the Context into a struct, explicitly passing in the function. The Context variable needs to be used as the first parameter, generally named CTX
Even if the method allows, do not pass in a nil context, if you are not sure what you want to use the context of the time to pass a context. Todo
The Value-related method using the context should only be used for metadata that is passed in the program and interface and requested, and should not be used to pass some optional arguments
The same context can be used to pass to different goroutine, the context is safe in multiple goroutine
Using the example
Example copy from: Introduction to the context package in Golang
Package Mainimport ("FMT" "Time" "Golang.org/x/net/context")//block function for simulating a minimum execution time Func Inc (a int) int {res: = a + 1//Although I only did a simple +1 operation, time. Sleep (1 * time. Second)//But since I have no such instruction in my machine instruction set,//So I finally get the result after I have executed 1 billion machine instructions and resumed 1s. b) return res}//to the externally supplied blocking interface//COMPUTE A + B, note A, B cannot be negative//If the calculation is interrupted, return -1func ADD (CTX context. Context, A, b int) int {res: = 0 for I: = 0; i < A; i++ {res = inc. (RES) SELECT {Case < -ctx. Done (): Return-1 Default:}} for I: = 0; I < b; i++ {res = Inc (RES) select {Case <-ctx. Done (): Return-1 Default:}} return Res}func main () {{//using an open API calculation a+b A: = 1 b: = 2 timeout: = 2 * time. Second CTX, _: = Context. Withtimeout (context. Background (), timeout) Res: = Add (CTX, 1, 2) fmt. Printf ("Compute:%d+%d, Result:%d\n", A, B, res)} {//HandMove cancel A: = 1 b: = 2 ctx, Cancel: = context. Withcancel (context. Background ()) go func () {time. Sleep (2 * time. Second) Cancel ()//Active cancel at Call} () Res: = Add (CTX, 1, 2) fmt. Printf ("Compute:%d+%d, Result:%d\n", A, B, res)}}