context
is a mechanism in Go that helps transmit cancellation signals, deadlines, and other request-scoped values across goroutines. It is especially useful in concurrent programming, where you need to manage the lifecycle of goroutines, handle timeouts, and propagate cancellation signals.
- Purpose: Manage and control the lifecycle of goroutines.
- How it works:
context
helps propagate cancellation, timeouts, and values between goroutines, without relying on global variables.
-
Creating a Context:
- Use functions from the
context
package likecontext.Background()
,context.TODO()
, andcontext.WithCancel()
to create a newcontext
.
- Use functions from the
-
Canceling a Context:
- Use
context.WithCancel()
to create a context that can be canceled when certain actions are completed.
- Use
-
Timeout and Deadline:
- Use
context.WithTimeout()
andcontext.WithDeadline()
to set a timeout for operations.
- Use
-
Passing Values in Context:
- You can use
context.WithValue()
to pass global values between goroutines.
- You can use
package main
import (
"context"
"fmt"
"time"
)
func main() {
// Create context with cancellation
ctx, cancel := context.WithCancel(context.Background())
// Goroutine performing work
go func() {
for {
select {
case <-ctx.Done():
// If context is canceled
fmt.Println("Operation canceled!")
return
default:
// Normal work
fmt.Println("Working...")
time.Sleep(1 * time.Second)
}
}
}()
// Cancel the context after 3 seconds
time.Sleep(3 * time.Second)
cancel()
// Wait for goroutine to finish
time.Sleep(1 * time.Second)
}
package main
import (
"context"
"fmt"
"time"
)
func main() {
// Create context with a 2-second timeout
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()
// Goroutine waits until timeout or completes work
go func() {
select {
case <-ctx.Done():
// Context expired
fmt.Println("Timed out!")
case <-time.After(3 * time.Second):
// Simulate work that takes 3 seconds
fmt.Println("Work completed")
}
}()
// Wait for goroutine to finish or timeout
time.Sleep(4 * time.Second)
}
package main
import (
"context"
"fmt"
)
func main() {
// Create context with value
ctx := context.WithValue(context.Background(), "userID", 12345)
// Goroutine reads value from context
go func(ctx context.Context) {
userID := ctx.Value("userID").(int)
fmt.Printf("User ID from context: %d\n", userID)
}(ctx)
// Wait for goroutine to finish
time.Sleep(1 * time.Second)
}
- Cancellation: Allows you to cancel ongoing tasks in goroutines when no longer needed.
- Timeouts and Deadlines: Controls the maximum duration for tasks and goroutines. If the task doesn’t complete within the allowed time, the context expires, signaling cancellation.
- Context Propagation: Transmits cancellation signals and values across API boundaries between goroutines.
-
Web Servers and HTTP Requests
- Scenario: Web applications handle multiple HTTP requests, each requiring a clear lifecycle with timeouts and cancellation if necessary.
- Solution: Use
context
to cancel HTTP requests if they exceed the timeout or if the client cancels the request.
-
Distributed Systems and API Calls
- Scenario: In distributed systems, API calls between services need to be managed with timeouts and cancellation.
- Solution: Use
context
to manage request lifetimes and propagate cancellation signals between services.
-
Parallel Operations
- Scenario: When executing multiple tasks concurrently, you may need to cancel tasks if one of them fails or exceeds its allocated time.
- Solution: Use
context
to cancel other goroutines when one task fails or exceeds the timeout.
- Use Context to Manage Timeouts and Cancellation: Always use context to manage timeouts and cancellations, especially when dealing with external APIs or services.
- Avoid Using Context for Global State: Context is not meant for passing global state. Use it to propagate cancellation, deadlines, or request-scoped values.
- Propagate Context Across API Boundaries: Always pass the context across API boundaries, especially when calling functions from other goroutines.
context
is a powerful tool for managing the lifecycle of goroutines, particularly when handling timeouts, cancellations, or propagating global values.- Understanding and using
context
correctly can help you avoid performance problems and resource management issues in concurrent or distributed applications.