Practical Waiting Methods
Comprehensive Job Completion Strategies
Golang provides multiple approaches to wait for job completion, each suited to different scenarios and complexity levels.
1. WaitGroup: Basic Synchronization
func basicWaitGroupExample() {
var wg sync.WaitGroup
for i := 0; i < 5; i++ {
wg.Add(1)
go func(id int) {
defer wg.Done()
time.Sleep(time.Second * time.Duration(id))
fmt.Printf("Job %d completed\n", id)
}(i)
}
wg.Wait()
fmt.Println("All jobs finished")
}
2. Channel-Based Waiting
Buffered Channel Synchronization
func channelWaitingMethod() {
jobs := 5
complete := make(chan bool, jobs)
for i := 0; i < jobs; i++ {
go func(id int) {
time.Sleep(time.Second * time.Duration(id))
fmt.Printf("Job %d finished\n", id)
complete <- true
}(i)
}
// Wait for all jobs
for i := 0; i < jobs; i++ {
<-complete
}
}
3. Context-Based Waiting
Timeout and Cancellation
func contextWaitingMethod() {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
done := make(chan bool)
go func() {
// Simulate long-running job
time.Sleep(3 * time.Second)
done <- true
}()
select {
case <-done:
fmt.Println("Job completed successfully")
case <-ctx.Done():
fmt.Println("Job timed out")
}
}
Waiting Method Comparison
Method |
Pros |
Cons |
Best Used For |
WaitGroup |
Simple, lightweight |
Limited error handling |
Parallel goroutine tracking |
Channels |
Flexible communication |
More complex setup |
Complex synchronization |
Context |
Timeout and cancellation |
Overhead for simple tasks |
Long-running or cancelable jobs |
4. Synchronization Primitives
Atomic Operations and Sync.Mutex
type SafeCounter struct {
mu sync.Mutex
counter int
}
func (c *SafeCounter) incrementWithWait() {
c.mu.Lock()
defer c.mu.Unlock()
c.counter++
}
Workflow Visualization
graph TD
A[Start Jobs] --> B{Waiting Method}
B --> |WaitGroup| C[Parallel Execution]
B --> |Channels| D[Synchronized Communication]
B --> |Context| E[Timeout/Cancellation]
C --> F[Completion Tracking]
D --> F
E --> F
F --> G[Final Result]
Advanced Waiting Techniques
Error Group Synchronization
func advancedErrorGroupWaiting() error {
g, ctx := errgroup.WithContext(context.Background())
for i := 0; i < 5; i++ {
id := i
g.Go(func() error {
select {
case <-ctx.Done():
return ctx.Err()
default:
return performJob(id)
}
})
}
return g.Wait()
}
LabEx Recommendation
At LabEx, we emphasize selecting the most appropriate waiting method based on specific use cases, balancing simplicity and functionality.
Best Practices
- Choose waiting method based on complexity
- Handle potential timeouts
- Implement proper error management
- Avoid blocking main goroutine unnecessarily
- Use context for complex cancellation scenarios