preface
Go1.7 introduces the Context package, which defines a variety of contexts, including actively cancelable contexts, contexts with cut-off or timeout times, and contexts with value propagation
The introduction of the context package makes it easier to pass information (such as user information) between coroutines and to control the exit timing of a group of coroutines
Let’s say we have a function gen, which takes context as an argument. It creates a bufferless channel, starts a coroutine to insert a signal into the channel every second. When the context ends, the channel is closed, and the coroutine exits normally
func gen(ctx context.Context) chan struct{} { c := make(chan struct{}) go func() { for { select { case <-ctx.Done(): }}}}}}}}}}}}}}}}}}}}}}}}}} If (c) // if (c) // if (c) // (struct struct{}{}) {// [2]} time.sleep (time.second)}()
Next, let’s walk through a few simple examples to experience the various types of contexts provided by the Context package
Example 1: Actively cancelable context
With the context package withCancel function, you can create a context that supports active cancellation
func UseCancelContext() { ctx, cancelFunc := context.WithCancel(context.Background()) go func() { time.AfterFunc(time.Second*5, CancelFunc () fmt.println ("send context done signal")})}() for range gen(CTX) {cancelFunc() fmt.println ("send context done signal")})}() for range gen(CTX) { fmt.Println("receive signal from another goroutine") } fmt.Println("main goroutine is finished") }
< -ctx.done () will have a value when the channel in the context is closed. Select in the gen function will select case < -ctx.done () and close the channel. Exit coroutines
The execution result of the function is as follows. It can be seen that the coroutine in the gen function closes the channel and exits the coroutine normally after sending signals for five times
<img src=”https://images-1255831004.cos.ap-guangzhou.myqcloud.com/online/2021-07-05-132126.png” alt=”image-20210705212126405″ style=”zoom:50%;” />
Example 2: Context with cutoff time
Using the context package withDeadline function, you can create a context with a deadline
CancelFunc := Context.withDeadline (Context.background ()), cancelFunc := Context.withDeadlineContext (), Time.now ().add (time.second *5)) defer cancelFunc() // [1] Why do you do it? for range gen(ctx) { fmt.Println("receive signal from another goroutine") } fmt.Println("main goroutine is finished") }
The above function creates a context with a cut-off time of five seconds, after which the channel closes
<img src=”https://images-1255831004.cos.ap-guangzhou.myqcloud.com/online/2021-07-05-133503.png” alt=”image-20210705213503229″ style=”zoom:50%;” />
Example 3: Context with timeout
Using the context package withTimeout function, you can create a context with a timeout
func UseTimeoutContext() {
ctx, cancelFunc := context.WithTimeout(context.Background(), time.Second*5)
defer cancelFunc()
for range gen(ctx) {
fmt.Println("receive signal from another goroutine")
}
fmt.Println("main goroutine is finished")
}
The above function creates a context with a five-second timeout, and the code executes the result
<img src=”https://images-1255831004.cos.ap-guangzhou.myqcloud.com/online/2021-07-05-133737.png” alt=”image-20210705213737346″ style=”zoom:50%;” />
Example 4: Context with value propagation
Using the context package withValue function, you can create a context WithValue propagation
Func usEvalueContext () {// create a context WithValue, key-value pair <1,"value"> CTX := context.withValue (context.background (), 1, "Value ") c := make(Chan struct{}) go func() {time.sleep (time.second * 1); fmt.Printf("get value from ctx, value = %s\n", value) c <- struct{}{} }() <-c fmt.Println("main goroutine is finished") }
The execution result
<img src=”https://images-1255831004.cos.ap-guangzhou.myqcloud.com/online/2021-07-05-134207.png” alt=”image-20210705214206616″ style=”zoom:50%;” />
conclusion
There are many scenarios where you need to use the context package in your daily development. Here are a few simple examples:
- Gets user information from the request context
- Gets the unique identity of the request from the request context (
traceId
, commonly used for distributed log tracing) - Controls the request timeout
As you can see, the context package makes it easier to propagate information among a group of coroutines and better control the exit timing of multiple coroutines
Go has also rewritten many of the standard libraries to support the context package
It is also recommended that the context should not be embedded in a structure. Instead, the context should be used as the first argument to a function/method called. It is recommended that the argument be named CTX
// Type ModuleContext struct {c context.context} // Func func1(CTX context.context, opts... Option)
It is essential to master the use of this package and understand how it works
In the next article I will answer the questions left in this article (Example 2)
[1]
) and to dig further
context
Package source