1package main
 2
 3import (
 4	"fmt"
 5	"runtime"
 6)
 7
 8func main() {
 9	goroutine := runtime.NumCPU()
10	chanSlice := make([]chan struct{}, 0)
11	chanExit := make(chan struct{}, 1)
12
13	for i := 0; i < goroutine; i++ {
14		chanSlice = append(chanSlice, make(chan struct{}, 1))
15	}
16
17	max := 100
18	num := 0
19
20	fmt.Println("runtime.NumCPU(): ", runtime.NumCPU())
21
22	for i := 0; i < goroutine; i++ {
23		go func(x int) {
24			for {
25				<-chanSlice[x]
26				num++
27				fmt.Println("goroutine: ", x, " chan: ", chanSlice[x], " num: ", num)
28
29				if num == max {
30					chanExit <- struct{}{}
31					break
32				}
33
34				chanSlice[(x+1)%goroutine] <- struct{}{}
35			}
36		}(i)
37	}
38
39	chanSlice[0] <- struct{}{}
40
41	select {
42	case <-chanExit:
43		fmt.Println("exit")
44	}
45
46	fmt.Println("goroutine: ", runtime.NumGoroutine())
47}

Run on Go Playground

改造下:

 1package main
 2
 3import (
 4	"fmt"
 5	"runtime"
 6	"sync"
 7)
 8
 9func main() {
10	var wg sync.WaitGroup
11	goroutine := runtime.NumCPU()
12	chanSlice := make([]chan struct{}, 0)
13	chanExit := make(chan struct{}, 1)
14
15	for i := 0; i < goroutine; i++ {
16		chanSlice = append(chanSlice, make(chan struct{}, 1))
17	}
18
19	max := 100
20	num := 0
21
22	fmt.Println("runtime.NumCPU(): ", runtime.NumCPU())
23
24	for i := 0; i < goroutine; i++ {
25		wg.Add(1)
26		go func(x int) {
27			defer wg.Done()
28			defer fmt.Println("exit goroutine: ", x)
29			for {
30				select {
31				case <-chanExit:
32					// close the next goroutine
33					chanExit <- struct{}{}
34					return
35
36				case <-chanSlice[x]:
37					num++
38					fmt.Println("goroutine: ", x, " chan: ", chanSlice[x], " num: ", num)
39
40					if num == max {
41						chanExit <- struct{}{}
42						break
43					}
44					chanSlice[(x+1)%goroutine] <- struct{}{}
45				}
46			}
47		}(i)
48	}
49
50	// start
51	chanSlice[0] <- struct{}{}
52	wg.Wait()
53
54	fmt.Println("goroutine: ", runtime.NumGoroutine())
55}

Run on Go Playground