Hi, I’m Mingo.

In their learning Golang this time, I wrote a detailed study notes on my personal number WeChat public Go programming time, for the language, I was a beginner, so writing should fit in with the new to classmates, if you are just learning the language, don’t focus on prevention, study together, Grow together.

My Github:github.com/iswbm/GolangCodingTime my online blog: golang.iswbm.com


In the first two articles, we learned about coroutines and channels, and there are many examples. To ensure that the main Goroutine is executed before exiting, I used a simple method called time.sleep.

Since all the demos written are relatively simple, sleep for 1 second is subjectively considered sufficient.

However, in real development, the developer cannot predict how long it will take all the Goroutine to complete. If there is more sleep, the main program will block. If there is less sleep, some subcoroutines will fail to complete their tasks.

Therefore, using time.sleep is not recommended, and today’s focus is on how to handle this gracefully.

1. Use channels to mark completion

“Don’t communicate by sharing memory, communicate by sharing memory.”

After learning the channel, we know that the channel can realize the communication between multiple coroutines, so we only need to define a channel, write true into the channel after the task is completed, and then get true in the main coroutine, and then consider that the sub-coroutine has been completed.

import "fmt"

func main() {
    done := make(chan bool)
    go func() {
        for i := 0; i < 5; i++ {
            fmt.Println(i)
        }
        done <- true
    }()
    <-done
}Copy the code

The output is as follows

0, 1, 2, 3, 4Copy the code

2. Use WaitGroup

The above method of using channels, in a single coroutine or a small number of coroutines, there will be no problem, but in a large number of coroutines, the code will appear very complex, interested in trying it yourself.

So is there a more elegant way?

Yes, which brings us to the WaitGroup type provided by the Sync package.

You can use WaitGroup as long as you instantiate it

Var Instance name sync.waitgroupCopy the code

Once instantiated, several of its methods can be used:

  • Add: The initial value is 0, and the value you pass in will Add to the counter, where you pass in the number of your child coroutines
  • Done: This method is called when a subcoroutine has finished, decrement one from the counter, and can usually be called using defer.
  • Wait: blocks the current coroutine until the counter in the instance is zero.

Here’s an example:

import (
    "fmt"
    "sync"
)

func worker(x int, wg *sync.WaitGroup) {
    defer wg.Done()
    for i := 0; i < 5; i++ {
        fmt.Printf("worker %d: %d\n", x, i)
    }
}

func main() {
    var wg sync.WaitGroup

    wg.Add(2)
    go worker(1, &wg)
    go worker(2, &wg)

    wg.Wait()
}Copy the code

The output is as follows

worker 2: 0
worker 2: 1
worker 2: 2
worker 2: 3
worker 2: 4
worker 1: 0
worker 1: 1
worker 1: 2
worker 1: 3
worker 1: 4Copy the code

This is how we implement one master and many child coroutine collaboration in Go, using sync.waitGroup is recommended.