SoFunction
Updated on 2025-03-04

How to wait for a set of coroutines to end

Go provides sync packages and channels to solve coroutine synchronization and communication.

Method 1:

It is to wait for a group of coroutines to end, there are only 3 methods, Add() adds a count, Done() subtracts a count, and Wait() blocks until all tasks are completed.

package main
import (
	"fmt"
	"sync"
	"time"
)
var wg  //Define a group that waits synchronouslyfunc task(i int){
	("task...",i)
	//Time-consuming operation of tasks, network requests, and reading files	()
	() //Subtract a count}
func main(){
	for i:= 0;i<10;i++{
		(1) //Add a count		go task(i)
	}
	() //Block until all tasks are completed	("over")
}

Running results:

task... 9

task... 4

task... 6

task... 0

task... 7

task... 5

task... 1

task... 2

task... 8

task... 3

over

Method 2:

Using buffer channel coroutine communication, its blocking and waiting function realizes waiting for a group of coroutines to end, and it cannot guarantee that its goroutine will be executed in sequence.

package main
import (
 "fmt"
)
var ch = make(chan int,10)
func task(i int){
 ("task...",i)
 ch <- i
}
func main(){
 for i:= 0;i<10;i++{
  go task(i)
 }
 for i:= 0;i<10;i++{
  <- ch
 } 
 ("over")
}

Running results:

task... 9

task... 0

task... 1

task... 2

task... 6

task... 7

task... 3

task... 4

task... 8

task... 5

over

Method 3:

Using unbuffered channel coroutines to communicate, its blocking and waiting function realizes waiting for a group of coroutines to end, ensuring that its goroutine is executed in sequence

package main
import (
 "fmt"
 "time"
)
var ch = make(chan int)
func task(i int){
 ("task...",i)
 ()
  <- ch
}
func main(){
 for i:= 0;i<10;i++{
  go task(i)
  ch <- i
 }
 ("over")
}

Running results:

task... 0

task... 1

task... 2

task... 3

task... 4

task... 5

task... 6

task... 7

task... 8

task... 9

over

Added: Use Channel in Go to wait for all coroutines to end

Let the main method wait for all coroutines to be executed before exiting. Perhaps the general idea is to set a common variable and then modify the state of this variable. This is how to communicate through shared variables, and what go needs to do is to share memory through communication.

1. Execute in order

Each communication is in pairs. When main sends a write channel to the coroutine, it also waits for the coroutine to return a read channel.

These two channels must be paired, so construct a structure

type worker struct {
    in chan int
    done chan bool
}
 
func chanDemo1(){
    var workers [10]worker 
    for i := 0; i < 10; i++ {
        workers[i] = createWorker1(i)
    }
 
    for i := 0; i < 10; i++ {
        workers[i].in <- 'a' + i
        <- workers[i].done
    }
 
    for i := 0; i < 10; i++ {
        workers[i].in <- 'A' + i
        <- workers[i].done
    } 
}
 
func createWorker1(id int) worker {
    work := worker{
        in: make(chan int),
        done: make(chan bool),
    }
    go func() {
        for {
            ("Work %d receiverd %c\n", id, <- )
             <- true
        }
    }()
    return  work
} 
 
func main(){
    chanDemo1()
    ("over")
}

This execution result is in the order of 0-9, lowercase and uppercase

If this order is executed, what else do coroutines do

2. Batch processing

type worker struct {
    in chan int
    done chan bool
}
 
func chanDemo1(){
    var workers [10]worker
    for i := 0; i < 10; i++ {
        workers[i] = createWorker1(i)
    }
    for i := 0; i < 10; i++ {
        workers[i].in <- 'a' + i
    }
    for _, worker  := range workers {
        <- 
    }
    for i := 0; i < 10; i++ {
        workers[i].in <- 'A' + i
    }
    for _, worker  := range workers {
        <- 
    }
}
 
func createWorker1(id int) worker {
    work := worker{
        in: make(chan int),
        done: make(chan bool),
    }
    go func() {
        for {
            ("Work %d receiverd %c\n", id, <- )
             <- true
        }
    }()
    return  work
}

In this case, print lowercase first and then uppercase, but the order in uppercase is not fixed

3. Completely random

func chanDemo1(){
    var workers [10]worker
    for i := 0; i &lt; 10; i++ {
        workers[i] = createWorker1(i)
    }
    for i := 0; i &lt; 10; i++ {
        workers[i].in &lt;- 'a' + i
    }
 
    for i := 0; i &lt; 10; i++ {
        workers[i].in &lt;- 'A' + i
    }
    for _, worker  := range workers {
        &lt;- 
        &lt;- 
    }
}
 
func createWorker1(id int) worker {
    work := worker{
        in: make(chan int),
        done: make(chan bool),
    }
    go func() {
        for {
            ("Work %d receiverd %c\n", id, &lt;- )
 
            // Open another coroutine            go func() {  &lt;- true}()
        }
    }()
    return  work
}

This is completely random

Use channel to traverse the tree

func (node *Node) TraverseFunc(f func(*Node)){
    if node == nil{
        return
    }
    (f)
    f(node)
    (f)
}
 
func (node *Node) TraverseWithChannel() chan *Node{
    out := make(chan *Node)
    go func() {
        (func(node *Node) {
            out <- node
        })
        close(out)
    }()
    return out
}
 
func main(){
    var root Node
    root = Node{Value:3}
     = &Node{}
     = &Node{5,nil,nil}
     = new(Node)
     =&Node{6,nil,nil}
    ()
 
    c:=()
    maxNode := 0
    for node := range c{
        if  > maxNode{
            maxNode = 
        }
    }
    ("max node value:", maxNode)
 

The above is personal experience. I hope you can give you a reference and I hope you can support me more. If there are any mistakes or no complete considerations, I would like to give you advice.