In Golang, you can synchronize coroutines with the Context, or pass Context variables to other coroutines. This avoids passing a large number of variables between coroutines and makes the code cleaner and maintainable. The following example passes a variable to a coroutine via WithValue and communicates between coroutines via channel.
package main
import (
"context"
"fmt"
"sync"
)
func worker(cancelCtx context.Context, ch chan int, wg *sync.WaitGroup) {
defer wg.Done()
fmt.Println(fmt.Sprintf("context value: %v", cancelCtx.Value("key1")))
for {
select {
case val := <-ch:
fmt.Println(fmt.Sprintf("read from ch value: %d", val))
case <-cancelCtx.Done():
fmt.Println("worker is cancelled")
return
}
}
}
func main() {
rootCtx := context.Background()
childCtx := context.WithValue(rootCtx, "key1", "value1")
cancelCtx, cancelFunc := context.WithCancel(childCtx)
ch := make(chan int)
wg := &sync.WaitGroup{}
wg.Add(1)
go worker(cancelCtx, ch, wg)
for i := 0; i < 10; i++ {
ch <- i
}
cancelFunc()
wg.Wait()
close(ch)
}
Copy the code
Output:
context value: value1
read from ch value: 0
read from ch value: 1
read from ch value: 2
read from ch value: 3
read from ch value: 4
read from ch value: 5
read from ch value: 6
read from ch value: 7
read from ch value: 8
read from ch value: 9
worker is cancelled
Copy the code
In a real production environment, such as a web server HTTP request handler, a generic field can be passed WithValue to a request processing coroutine, such as link tracing between multiple requests:
package main import ( "context" "fmt" "net/http" "github.com/google/uuid" ) func welcome(w http.ResponseWriter, r *http.Request) { traceid := "" if m := r.Context().Value("traceid"); m ! = nil { if value, ok := m.(string); ok { traceid = value } } w.Header().Add("traceid", traceid) w.Write([]byte("Welcome to China")) } func traceID(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { traceid := uuid.New().String() ctx := context.WithValue(r.Context(), "traceid", traceid) req := r.WithContext(ctx) next.ServeHTTP(w, req) }) } func main() { welcomeHandler := http.HandlerFunc(welcome) http.Handle("/welcome", traceID(welcomeHandler)) http.ListenAndServe(":9090", nil) }Copy the code