Developing Golang to gain a deeper understanding of context

The history of context

The context package has been officially added to the Go standard library in Go version 1.7. Before joining, let’s take a look at Sameer Ajmani, a core member of the Go team, who published a blog in 2014 introducing context. The address is: https://go.dev/blog/context Here is the translation of the introduction.

In the Go server, each incoming request is processed in its own goroutine. Request handlers often initiate additional goroutines to access the backend, such as databases and RPC services. The goroutine collection for processing requests typically requires access to request specific values, such as the end user’s identity, authorization token, and request deadline. When a request is cancelled or timed out, all goroutines handling the request should exit quickly so that the system can reclaim any resources they are using.
At Google, we have developed a context package that easily passes the values, cancellation signals, and deadlines within the request range across API boundaries to all goroutines involved in processing the request. This software package is publicly available as a context.

It can be seen that the introduction mainly discusses how to control a large number of goroutines to exit and release resources in the application, and how to pass values within the request range. In other words, the introduction of context is mainly to solve these two problems.

Basic usage of context

There are five methods for initializing context, one is main goroutine initialization, and the other is mainly used for passing values. There are only three commonly used methods.

When the timeout is not exceeded, execute the cancellation, relying on the cancellation function

func main() {
    ctx := context.Background()
    ctx = context.WithValue(ctx, "main", "main-value")

    ctx1,cancel := context.WithDeadline(ctx, time.Now().Add(3*time.Second))
    go cancelFunc(ctx1)
    
    cancel()
    time.Sleep(time.Duration(5*time.Second))
}


main-param main-value

When timeout occurs, execute the result. If the timeout exceeds three seconds, it depends on the timeout time

func main() {
    ctx := context.Background()
    ctx = context.WithValue(ctx, "main", "main-value")

    ctx1,_ := context.WithDeadline(ctx, time.Now().Add(3*time.Second))
    go cancelFunc(ctx1)
    time.Sleep(time.Duration(5*time.Second))
}

// Execution result
Main parameter main-value
1 second
1 second
1 second
Goroutine exited

Based on the comments and execution process, I can basically understand that calling cancel in the main function can cancel the executing goroutine coroutine. WithDeadline and WithTimeout can not only be cancelled by calling the cancel function, but also by setting a timeout point and time period to cancel the execution of goroutine.

How to control multiple goroutines in context and how to pass values to multiple goroutines

As shown in the diagram, root context controls all goroutines, context 1 controls goroutine2 goroutine3 goroutine4 goroutine5 goroutine6 goroutine7, context 2 controls goroutine4 goroutine5, and context 3 controls goroutine6 goroutine7.

Write test code using the goroutine shown in the diagram

package main

import (
    "context"
    "fmt"
    "time"
)

func func1(ctx context.Context) {
    fmt.Println("func1-main-param", ctx.Value("main"))
    ctx1 := context.WithValue(ctx, "func1-param", "func1-value")
    go func2(ctx1)
    select {
    case <-ctx1.Done():
        fmt.Println("goroutine 1 exit")
    }
}

func func2(ctx context.Context) {
    fmt.Println("func2-main-param", ctx.Value("main"))
    fmt.Println("func2-func1-param", ctx.Value("func1-param"))
    ctx2, _ := context.WithCancel(ctx)
    go func4(ctx2)
    go func5(ctx2)
    select {
    case <-ctx2.Done():
        fmt.Println("goroutine 2 exit")
    }
}

func func4(ctx context.Context) {
    select {
    case <-ctx.Done():
        fmt.Println("goroutine 4 exit")
    }
}

func func5(ctx context.Context) {
    select {
    case <-ctx.Done():
        fmt.Println("goroutine 5 exit")
    }
}

func main() {
    ctx := context.Background()
    ctx = context.WithValue(ctx, "main", "main-value")
    ctx,cancel := context.WithCancel(ctx)
    go func1(ctx)
    cancel()
    time.Sleep(time.Duration(5*time.Second))
}

Running results

func1-main-param main-value
goroutine 1 exit
func2-main-param main-value
func2-func1-param func1-value
goroutine 2 exit
goroutine 5 exit
goroutine 4 exit

Title of this article:<Developing Golang to gain a deeper understanding of context>Author:minimini
Original link:https://www.xxmjw.com/post/26.html
Unless otherwise specified, all content is original. Please indicate when reprinting.

Related

minimini

minimini