SoFunction
Updated on 2025-03-05

Detailed explanation of WaitGroup usage examples in the Go basic tutorial series

Under normal circumstances, the ending process of the newly activated goroutine (coroutine) is uncontrollable. The only thing that can guarantee that the ending of goroutine (coroutine) is the termination of the main goroutine (coroutine). That is, we don't know when which goroutine (coroutine) ends.

But in many cases, we need to know whether the goroutine (coroutine) is completed. This needs to be achieved by using WaitGroup of the sync package.

WatiGroup is a struct type in the sync package, used to collect goroutines (coroutines) that need to wait for execution to complete. Here is its definition:

type WaitGroup struct {
        // Has unexported fields.
}
    A WaitGroup waits for a collection of goroutines to finish. The main
    goroutine calls Add to set the number of goroutines to wait for. Then each
    of the goroutines runs and calls Done when finished. At the same time, Wait
    can be used to block until all goroutines have finished.

    A WaitGroup must not be copied after first use.


func (wg *WaitGroup) Add(delta int)
func (wg *WaitGroup) Done()
func (wg *WaitGroup) Wait()

It has 3 methods:

  • Add(): Before activate the goroutine (coroutine) that wants to be completed, call Add() first to set or add the number of goroutine (coroutine) to wait for completion.
    • For example, Add(2) or two calls to Add(1) will set the value of the waiting counter to 2, indicating that you have to wait for 2 goroutines (coroutines) to complete
  • Done(): Before each goroutine (coroutine) that needs to be waited for, this method should be called to artificially indicate that the goroutine (coroutine) has been completed. This method will decrement the wait counter by 1.
  • Wait(): Wait() will block the current goroutine (coroutine) before waiting for the counter to decrease to 0.

In other words, Add() is used to increase the number of goroutines to wait, Done() is used to indicate that goroutines have been completed, and reduce the counter once, and Wait() is used to wait for all goroutines to wait for completion.

Here is an example, which is easy to understand through examples.

package main

import (  
    "fmt"
    "sync"
    "time"
)

func process(i int, wg *) {  
    ("started Goroutine ", i)
    (2 * )
    ("Goroutine %d ended\n", i)
    ()
}

func main() {  
    no := 3
    var wg 
    for i := 0; i < no; i++ {
        (1)
        go process(i, &wg)
    }
    ()
    ("All go routines finished executing")
}

Three goroutines are activated above. Before each goroutine is activated, the Add() method is called to increase the goroutine count that needs to be waited for. Each goroutine runs the process() function. When this function is completed, it needs to call the Done() method to indicate the end of the goroutine. After activate 3 goroutines, the main goroutine will be executed to Wait(). Since each activated goroutine runs process() requires 2 seconds to sleep, the main goroutine will block for a period of time (about 2 seconds). When all goroutines are completed, wait for the counter to decrease to 0, Wait() will no longer block, so the main goroutine can execute the subsequent Println().

Another thing to pay special attention to isUse pointer type in process()*As parameter, value type cannot be used hereAs a parameter, because this means that each goroutine copies a copy of wg and each goroutine uses its own wg. This is obviously unreasonable.These 3 goroutines should share a wg, only then can you know that these 3 goroutines have been completed. In fact, if a parameter of value type is used, the main goroutine will permanently block, resulting in a deadlock.

More AboutGo WaitGroup Usage TutorialPlease check the related links below