golang 实现 cat fish dog goroutine 交替打印100次

373 阅读2分钟

最近遇到一个程序设计题,这里分享下。

当时遇到后,觉得应该是用到 channel 但对于具体怎样用,当时一时没想到怎么实现,这里记录下通过 多channel + mod运算 + sync.WaitGroup 实现。

下面是通过大模型给出的答案,供参考。 在Go语言中,确保goroutine按特定顺序执行(比如,依次打印"cat", "fish", "dog")是一个常见的同步问题。由于goroutine的执行是并发的,我们需要使用某种同步机制来控制它们的执行顺序。一种常见的方法是使用通道(channel)和等待组(sync.WaitGroup)来同步goroutine的执行。但是,为了按照特定顺序执行,仅使用sync.WaitGroup是不够的,因为sync.WaitGroup只能用来等待一组goroutine完成,而不能确保它们以特定顺序执行。

这里,我们可以使用带缓冲的通道来同步这些打印操作。具体来说,我们可以创建一个包含三个通道的数组,每个通道代表一个阶段,每个阶段只有当前阶段的goroutine能写入,下一个阶段的goroutine能读取。通过这种方式,我们可以确保打印操作按照"cat", "fish", "dog"的顺序进行。

以下是一个实现示例:

package main

import (
	"fmt"
	"sync"
)

func main() {
	var wg sync.WaitGroup
	// 创建三个带缓冲的通道
	stages := [3]chan bool{make(chan bool, 1), make(chan bool, 1), make(chan bool, 1)}

	// 初始化第一个阶段,使其可以直接开始
	stages[0] <- true

	// 启动goroutine
	for i := 0; i < 3; i++ {
		wg.Add(1)
		go func(i int, stages [3]chan bool) {
			defer wg.Done()
			var animal string
			switch i {
			case 0:
				animal = "cat"
			case 1:
				animal = "fish"
			case 2:
				animal = "dog"
			}
			for j := 0; j < 100; j++ {
				<-stages[i] // 等待前一个阶段完成
				fmt.Println(animal)
				stages[(i+1)%3] <- true // 通知下一个阶段可以开始
			}
		}(i, stages)
	}

	wg.Wait() // 等待所有goroutine完成
	close(stages[0]) // 关闭通道,实际上在这个例子中不需要,因为我们不会再读取它们
	close(stages[1])
	close(stages[2])
}

注意:

  1. 我们使用了一个[3]chan bool的数组stages,其中每个元素都是一个带有一个缓冲区的通道。这些通道用于在不同的goroutine之间进行同步。
  2. 每个goroutine在开始打印前都会从它自己的通道中接收一个值(这里使用true作为占位符),这确保了它只在接收到信号时才开始执行。
  3. 在完成打印后,goroutine会向下一个阶段的通道发送一个信号(即发送true),以便下一个goroutine可以开始执行。
  4. 由于有三个阶段,我们使用(i+1)%3来计算下一个阶段的索引,以确保索引在循环时能够正确回绕。
  5. 使用sync.WaitGroup来等待所有goroutine完成。

这种方法确保了即使在不同的goroutine中,打印操作也会按照"cat", "fish", "dog"的顺序循环进行。