Go’s New WaitGroup.Go



This content originally appeared on DEV Community and was authored by Joy Biswas

Go 1.25+ added a new method to the sync package that removes common boilerplate: the WaitGroup.Go() method. If you’ve used wg.Add(1), go func(), and defer wg.Done() hundreds of times, this one’s for you.

The old way

Here’s how we launch concurrent goroutines:

package main

import (
    "fmt"
    "sync"
)

func main() {
    var wg sync.WaitGroup
    list1 := []int{10, 20, 30, 40}
    list2 := []int{1, 10, 20, 30, 40}

    l1 := []int{-1, 4, 5, 6}
    l2 := []int{4, 5, 6}

    wg.Add(1)
    go func() {
        defer wg.Done()
        solution(list2, list1)
    }()

    wg.Add(1)
    go func() {
        defer wg.Done()
        solution(l2, l1)
    }()

    wg.Wait()
}

func solution(x, y []int) {
    var uniqueIdx int
    for _, num1 := range x {
        uniqueIdx ^= num1
    }
    for _, num2 := range y {
        uniqueIdx ^= num2
    }
    fmt.Println(uniqueIdx)
}

This works fine. But look at the steps: increment the counter manually, wrap everything in an anonymous function, remember to defer the done call. For every single goroutine.

The new way

Now we can write:

package main

import (
    "fmt"
    "sync"
)

func main() {
    var wg sync.WaitGroup
    list1 := []int{10, 20, 30, 40}
    list2 := []int{1, 10, 20, 30, 40}

    l1 := []int{-1, 4, 5, 6}
    l2 := []int{4, 5, 6}

    wg.Go(func() {
        solution(list1, list2)
    })
    wg.Go(func() {
        solution(l2, l1)
    })

    wg.Wait()
}

func solution(x, y []int) {
    var uniqueIdx int
    for _, num1 := range x {
        uniqueIdx ^= num1
    }
    for _, num2 := range y {
        uniqueIdx ^= num2
    }
    fmt.Println(uniqueIdx)
}

The Go() method handles the counter increment and the Done() call automatically. Three steps become one clean method call.

What it does

The implementation is simple:

// https://github.com/golang/go/blob/master/src/sync/waitgroup.go
func (wg *WaitGroup) Go(f func()) {
    wg.Add(1)
    go func() {
        defer wg.Done()
        f()
    }()
}

It’s exactly what we’ve been writing manually, just packaged properly.

If you’re on Go 1.25 or later, start using wg.Go() where it makes sense.

Thanks to Anton Zhiyanov for his excellent Gist of Go: Concurrency guide.


This content originally appeared on DEV Community and was authored by Joy Biswas