Go 使用协程编写程序,按顺序打印 cat、dog、fish ,依次打印十次

请尝试在评论区里写下答案(如不能清楚表述,那么你可能没真正理解)。欢迎参与,为下一次求职做准备。

V1 Add

package main

import (
    "fmt"
    "sync"
)

func main() {
    var wg sync.WaitGroup
    wg.Add(3)

    catCh := make(chan struct{})
    dogCh := make(chan struct{})
    fishCh := make(chan struct{})

    // 打印cat的协程
    go func() {
        defer wg.Done()
        for i := 0; i < 10; i++ {
            <-catCh
            fmt.Println("cat")
            dogCh <- struct{}{}
        }
    }()

    // 打印dog的协程
    go func() {
        defer wg.Done()
        for i := 0; i < 10; i++ {
            <-dogCh
            fmt.Println("dog")
            fishCh <- struct{}{}
        }
    }()

    // 打印fish的协程
    go func() {
        defer wg.Done()
        for i := 0; i < 10; i++ {
            <-fishCh
            fmt.Println("fish")
            if i < 9 {
                catCh <- struct{}{}
            } else {
                // 9 退出
                break
            }
        }
    }()

    // 启动第一个协程
    catCh <- struct{}{}

    wg.Wait()
}

V2 update 2023-12-21

package main

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

var wg sync.WaitGroup

func main() {
    ch1 := make(chan struct{}, 1)
    ch2 := make(chan struct{}, 1)
    ch3 := make(chan struct{}, 1)

    wg.Add(3)
    start := time.Now().Unix()
    // 这里的 三个必须都是10,否则有的 channel 关闭,再进行写入报错
    total := 10
    // 触发动作
    ch1 <- struct{}{}
    go handle("CAT", total, ch1, ch2)
    go handle("DOG", total, ch2, ch3)
    go handle("FISH", total, ch3, ch1)
    wg.Wait()
    end := time.Now().Unix()
    fmt.Printf("cost:%d", end-start)
}

// go goroutine
func handle(name string, nums int, inputChan chan struct{}, outputChan chan struct{}) {
    defer wg.Done()
    for i := 0; i < nums; i++ {
        // 这里休眠可以感受到 3个 goroutine 的并发执行,而不是串行,1秒中,输出三个
        time.Sleep(1 * time.Second)
        select {
        case <-inputChan:
            fmt.Printf("%s \n", name)
            outputChan <- struct{}{}
        }
    }
}
明天我们吃什么 悲哀藏在现实中 Tacks
讨论数量: 4

请教一下为什么wg.Wait()放到发送通道之前会导致死锁

1年前 评论
Tacks (楼主) 1年前
zev3691 (作者) 1年前

可以看一下 sync.WaitGroup 这个包的相关作用。WaitGroup 用于等待一组 goroutine 的结束,并且阻塞主线程的执行,直到所有的 goroutine 执行完成。

  • Add()
    • 主函数中也就是主线程中调用Add() 方法来设定应等待的协程的数量
  • Done()
    • 而每个被等待执行的 Go 协程在结束时应调用 Done() 方法,实际上就相当于 Add(-1)
  • Wait()
    • 那么 Wait()操作就是用来执行阻塞,直到所有的 WaitGroup 数量变成 0

如果 wg.Wait () 放到 catCh <- struct{}{} 前面,goroutine 等待 channel 里面的数据,但是此时还没有给 catCh 信号,而 wg 又一致阻塞等待 goroutine 执行,因此会死锁。

大概是这样,不知道回答的是否准确

1年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!