题目描述

使用两个 goroutine 交替打印序列,一个 goroutine 打印数字, 另外一个 goroutine 打印字母, 最终效果如下:

1A2B3C4D5E6F7G8H9I10J11K12L13M14N15O16P17Q18R19S20T21U22V23W24X25Y26Z

思路

使用 channel 来控制打印的进度。使用两个 channel,来分别控制数字和字母的打印进度,数字打印完通过 channel 通知数字打印,数字打印完通过 channel 通知字母打印。如此周而复始,直到终止条件。

代码参考

func printEach() {
    letter, number := make(chan bool), make(chan bool)
    wait := sync.WaitGroup{}

    go func() {
        i := 1
        for {
            select {
            case <-number:
                fmt.Print(i)
                i++
                letter <- true
            }
        }
    }()
    wait.Add(1)
    go func(wait *sync.WaitGroup) {
        str := "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
        i := 0
        for {
            select {
            case <-letter:
                if i >= len(str) {
                    wait.Done()
                    return
                }
                fmt.Print(str[i : i+1])
                i++
                if i >= len(str) {
                    wait.Done()
                    return
                }
                number <- true
            }

        }
    }(&wait)
    // 让数字先开始打印
    number <- true
    // 等待循环结束,表示整个打印可以结束了
    wait.Wait()
    // 最后关闭 channel,防止内存泄露
    close(letter)
    close(number)
}

代码解释:
letter 用于通知打印字母,number 用于通知打印数字。
sync.Waitgroup{} 用于阻塞主线程等待整个打印过程结束。
倒数第 4 行中的 number <- true 表示让数字先开始打印。
结束后记得关闭 channel,防止内存泄露

扩展

有三个函数,分别可以打印 “cat” “dog” “fish”,要求每个函数都起一个 goroutine,并按照 “cat” “dog” “fish” 的顺序打印在屏幕上,5 次。

func printCatDogFish(){
    cat, dog, fish := make(chan struct{}), make(chan struct{}), make(chan struct{})
    wg := &sync.WaitGroup{}

    target := 100

    go func() {
        // cat
        for {
            select {
            case <-cat:
                fmt.Println("cat")
                dog <- struct{}{}
            }
        }
    }()

    go func() {
        // dog
        for {
            select {
            case <-dog:
                fmt.Println("dog")
                fish <- struct{}{}
            }
        }
    }()

    wg.Add(1)
    go func(w *sync.WaitGroup) {
        // fish
        defer w.Done()
        i := 0
        for {
            select {
            case <-fish:
                fmt.Println("fish")
                i++
                if i >= target {
                    return
                }
                cat <- struct{}{}
            }
        }
    }(wg)

    cat <- struct{}{}

    wg.Wait()
    close(cat)
    close(dog)
    close(fish)
}