# Golang Concurrency #7 - WaitGroup

# Introduction

WaitGroups solve the problem: "How do I wait for multiple goroutines to finish?"

# The Problem

```go
func main() {
    go doWork("Job 1")
    go doWork("Job 2")
    go doWork("Job 3")

    fmt.Println("All done!")  // Prints immediately, jobs still running
}
```

Main function exits before goroutines finish. You need to wait for them.

# Bad Solution

```go
func main() {
    go doWork("Job 1")
    go doWork("Job 2")
    go doWork("Job 3")

    time.Sleep(5 * time.Second)  // Guess how long to wait
    fmt.Println("All done!")
}
```

What if jobs take 6 seconds? What if they take 1 second? You're either waiting too long or not long enough.

# Good Solution -&gt; WaitGroup

```go
func main() {
    var wg sync.WaitGroup

    wg.Add(3)  // "I'm expecting 3 goroutines to finish"

    go doWork("Job 1", &wg)
    go doWork("Job 2", &wg)
    go doWork("Job 3", &wg)

    wg.Wait()  // Block until all 3 call Done()
    fmt.Println("All done!")
}

func doWork(name string, wg *sync.WaitGroup) {
    defer wg.Done()  // "I'm finished" (decrements counter)

    fmt.Printf("Starting %s\n", name)
    time.Sleep(2 * time.Second)  // Simulate work
    fmt.Printf("Finished %s\n", name)
}
```

# How WaitGroup works

1. `Add(3)` sets internal counter to 3
    
2. Each `Done()` decrements the counter (3→2→1→0)
    
3. `Wait()` blocks until counter reaches 0
    

# Common pattern

```go
var wg sync.WaitGroup

for i := 0; i < 10; i++ {
    wg.Add(1)
    go func(jobID int) {
        defer wg.Done()
        processJob(jobID)
    }(i)
}

wg.Wait()  // Wait for all 10 jobs
```

# Important rules

* Always call `Add()` before starting goroutines
    
* Always call `Done()` exactly once per goroutine
    
* Use `defer wg.Done()` to ensure it runs even if goroutine panics
    

WaitGroups are like taking attendance -&gt; you know how many people you're expecting, and you wait until everyone checks in.
