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:

  1. Gets user information from the request context
  2. Gets the unique identity of the request from the request context (traceId, commonly used for distributed log tracing)
  3. 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
contextPackage source