代码参考至 《Go语言精进之路》

例子1

package main

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

type signal struct{}

func worker(i int) {
	fmt.Printf("worker %d :is working... \n", i)
	time.Sleep(time.Duration(i) * time.Second)
	fmt.Printf("worker %d :is done... \n", i)
}

func spawnGroup(f func(i int), num int, groupSignal <-chan signal) <-chan signal {
	c := make(chan signal)
	var wg sync.WaitGroup
	for i := 0; i < num; i++ {
		time.Sleep(1 * time.Second)
		wg.Add(1)

		go func(i int) {
			<-groupSignal
			fmt.Printf("worker %d :start to work...\n", i)
			f(i)
			wg.Done()

		}(i + 1)
	}
	go func() {
		wg.Wait()
		c <- signal{}
	}()
	return c
}
func main() {
	println("start a")
	groupSignal := make(chan signal)
	c := spawnGroup(worker, 5, groupSignal)
	time.Sleep(5 * time.Second)
	close(groupSignal)
	<-c
	println("done")
}

输出

start a
worker 3 :start to work...
worker 3 :is working...   
worker 1 :start to work...
worker 1 :is working...   
worker 5 :start to work...
worker 5 :is working...   
worker 2 :start to work...
worker 2 :is working...   
worker 4 :start to work...
worker 4 :is working...   
worker 1 :is done... 
worker 2 :is done... 
worker 3 :is done... 
worker 4 :is done... 
worker 5 :is done... 
done

例子2


package main

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

type signal struct{}

func worker(i int) {
	fmt.Printf("worker %d :is working... \n", i)
	time.Sleep(time.Duration(i) * time.Second)
	fmt.Printf("worker %d :is done... \n", i)
}

func spawnGroup(f func(i int), num int, groupSignal <-chan signal) <-chan signal {
	c := make(chan signal)
	var wg sync.WaitGroup
	for i := 0; i < num; i++ {
		time.Sleep(1 * time.Second)
		wg.Add(1)

		go func(i int) {
			// <-groupSignal
			fmt.Printf("worker %d :start to work...\n", i)
			f(i)
			wg.Done()

		}(i + 1)
	}
	go func() {
		wg.Wait()
		c <- signal{}
	}()
	return c
}
func main() {
	println("start a")
	groupSignal := make(chan signal)
	c := spawnGroup(worker, 5, groupSignal)
	time.Sleep(5 * time.Second)
	// close(groupSignal)
	<-c
	println("done")
}

输出

start a
worker 1 :start to work...
worker 1 :is working... 
worker 1 :is done... 
worker 2 :start to work...
worker 2 :is working...   
worker 3 :start to work...
worker 3 :is working... 
worker 2 :is done... 
worker 4 :start to work...
worker 4 :is working...   
worker 5 :start to work...
worker 5 :is working... 
worker 3 :is done... 
worker 4 :is done... 
worker 5 :is done... 
done

前者的goruntime在启动后会堵塞在名为groupSignal的无缓存的channel上,等main goroutine通过close(groupSignal)后,所有goroutine会同时启动运行,关闭一个无缓存channel会让所有堵塞在该channel上的接收操作返回,实现一种一对多的广播机制,而后者在启动goruntime后就立即执行相应的流程,适用一般的流程中