DEV Community

Joy Biswas
Joy Biswas

Posted on

Go's New WaitGroup.Go

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)
}
Enter fullscreen mode Exit fullscreen mode

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)
}
Enter fullscreen mode Exit fullscreen mode

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()
    }()
}
Enter fullscreen mode Exit fullscreen mode

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.

Top comments (0)