This is the fourth day of my participation in the August More text Challenge. For details, see:August is more challenging
Context
Context.Context is used to set deadlines, synchronize signals, and transmit request-related structures in Go language.Context has a close relationship with Gotoutine, and is a unique design in Go language.
The Context effect
- Every Context is passed from the top Goroutine to the bottom one layer at a time.Context.Context can make an error in the execution of the upper Goroutine and synchronize the signal to the next layer in time, so that if the upper layer fails for some reason, The underlying layer can then stop useless work and reduce resource consumption. Actual application: Set the RPC timeout period
- Context. WithValue can create a subcontext from the parent context. The subcontext that passes the value uses the context.valuectX type. WithValue is a pair of kV types that can be used to pass values. Practical application: pass globally unique call chains
The Context interface
Context is a standard library interface introduced by the Go language in version 1.7. The following methods need to be implemented
- Deadlime returns the context. The time when the context was cancelled, which is the deadline for completing the work
- Done returns a Channel that will be closed when the current work is completed or cancelled. Multiple calls to Done will return the same Channel
- Err returns context. The reason for the end of context will only return a non-null value when the Channel corresponding to the Done method is closed
- Value gets its corresponding Value from context. context. For the same context, calling Value multiple times with the same Key will return the same result. Modifiers can be used to pass specific requests.
- If context. context is Canceled, a cancellation error is returned.
- If context. context times out, a DeadlineExceeded error will be returned;
type Context interface {
Deadline() (deadline time.Time, ok bool)
Done() <-chan struct{}
Err() error
Value(key interface{}) interface{}}Copy the code
Use context to synchronize signals
Create a context with an expiration time of 1s and pass handle to it. The method takes 500ms to process the incoming request.
Package ContextTtest import ("context" "FMT" "testing" "time") func TestContext(t *testing.T) {// Create a contextTtest import ("context" "FMT" "testing" "time") cancel := context.WithTimeout(context.Background(), 1*time.Second) defer cancel() go handle(ctx, 500*time.Millisecond) select { case <-ctx.Done(): fmt.Println("main", ctx.Err()) } } func handle(ctx context.Context, duration time.Duration) { select { case <-ctx.Done(): fmt.Println("handle", ctx.Err()) case <-time.After(duration): fmt.Println("process request with", duration) } }Copy the code
Running result:
=== RUN TestContext process Request with 500ms main context deadline exceeded -- PASS: TestContext (1.00s) PASSCopy the code
The Context to create
- Root Context: Created with context.background ()
- Subconetxt: Context. WithCancel(parentConetxt) is created
ctx, cancel := context.WithCancel(conetext.Background())
Copy the code
- When the current Context is cancelled, all other sub-contexts are cancelled
- Receive cancellation notifications < -ctx.done ()
Test the code Package Main
import (
"context"
"testing"
"time"
)
func isCanceled(ctx context.Context) bool {
select {
case <-ctx.Done():
return true
default:
return false
}
}
func TestCanceledByConetxt(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
for i := 0; i < 5; i++ {
go func(i int, ctx context.Context) {
for {
if isCanceled(ctx) {
break
}
}
time.Sleep(time.Second * 1)
}(i, ctx)
}
cancel()
}
Copy the code