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{}{}
}
}
}
请教一下为什么wg.Wait()放到发送通道之前会导致死锁
可以看一下
sync.WaitGroup
这个包的相关作用。WaitGroup 用于等待一组goroutine
的结束,并且阻塞主线程的执行,直到所有的goroutine
执行完成。Add()
方法来设定应等待的协程的数量Done()
方法,实际上就相当于Add(-1)
Wait()
操作就是用来执行阻塞,直到所有的 WaitGroup 数量变成 0如果
wg.Wait ()
放到catCh <- struct{}{}
前面,goroutine 等待 channel 里面的数据,但是此时还没有给 catCh 信号,而 wg 又一致阻塞等待 goroutine 执行,因此会死锁。大概是这样,不知道回答的是否准确