问了 ds, 解释的有点 get 不到,求大佬详细解释下
package main
import (
"fmt"
"sync"
)
func main() {
var wg sync.WaitGroup
prev := make(chan struct{})
current := make(chan struct{})
prev = current
for id := 1; id <= 10; id++ {
wg.Add(1)
next := make(chan struct{})
go func(id int, prev <-chan struct{}, next chan<- struct{}) {
defer wg.Done()
<-prev
fmt.Println(id)
if id < 10 {
close(next)
}
}(id, prev, next)
prev = next
}
close(current)
wg.Wait()
}
![]() |
1
LitterGopher 22 天前
關鍵在於 `next := make(chan struct{})` 這一行代碼, 每次循環都會創建一個新的 chan, 在閉包中只有等 prev 被寫入/或關閉的時候讀取纔會結束, 然後纔會繼續後面的內容, 然而這個 prev 每次都被 next 重新填充, 所以除了第一個 goroutine 後面的所有 goroutine 都是上一個循環創建的 next. 所以要等上一個 next 關閉或被寫入. 所以只有在第一個被寫入後才能依次出發後面的 goroutine 執行, 而每一個 goroutine 中 close(next) 實際上就是在對下一個 goroutine close(prev)
|
![]() |
2
LitterGopher 22 天前
這寫法雖然有點意思, 但是不推薦這樣寫.
|
![]() |
3
yuntun 22 天前
通过 prev <-chan struct{}和 next chan<- struct{} 的机制, id=1 的 goroutine 等待 current 被关闭,最先被唤醒;
然后打印 1 ,然后关闭 next , 也就是传给 id=2 的 prev, id=2 的 goroutine 被唤醒,打印 2 ,然后关闭他的 next , 整个链条顺序唤醒,顺序打印,直到 id=10 。 |
![]() |
4
bronyakaka 22 天前
每个 goroutine 的 prev channel 是前一个 goroutine 的 next channel 。每个 goroutine 在执行打印之前会等待从 prev channel 接收信号,打印完成后会向 next channel 发送信号(通过关闭 channel )。
|
5
iceheart 22 天前 via Android
就像,烽火台
|
6
zxjxzj9 21 天前
就像接力棒,第一棒( current )在循环外交给了第一个 goroutine ,然后在每个 goroutine 里都把当前这个接力棒小给下一个 goroutine 后退出。程序干的事情实际是一口气开 10 个 goroutine (好比跑道上已经准备好了 10 个人),然后在循环外把第一个 channel 丢给了 id 是 1 的 goroutine ,之后依次往下接力
|
![]() |
7
AkinoKaedeChan 21 天前 via iPhone
类似 PV 操作,把 close 看成 V 操作,把 <- 看成 P 操作,变量被反复修改了,其实可以看成共 10 个信号量。
|
8
zzhaolei 21 天前
击鼓传花。可以这么写,没必要创建一个新的 channel ,还需要回收:
``` prev := make(chan struct{}) start := prev ... close(start) ``` |
![]() |
9
minchieh 20 天前 ![]() 基础知识:chan 类型变量是引用传递(子函数给赋值 会改变原值)
加入 2 行代码。真相就出来了 ------------------------------------------------------------------ go func(id int, prev <-chan struct{}, next chan<- struct{}) { defer wg.Done() fmt.Printf("我是%d 我在等%p\n", id, prev) <-prev fmt.Println(id) if id < 10 { fmt.Printf("========我是%d 我放行了%p\n", id, next) close(next) } }(id, prev, next) -------------------------------------------------------------------------------- 看打印: 初始的 prev:0x140000221c0 我是 10 我在等 0x140000225b0 我是 6 我在等 0x140000223f0 我是 7 我在等 0x14000022460 我是 8 我在等 0x140000224d0 我是 9 我在等 0x14000022540 我是 2 我在等 0x14000022230 我是 4 我在等 0x14000022310 我是 5 我在等 0x14000022380 我是 1 我在等 0x140000221c0 1 我是 3 我在等 0x140000222a0 ========我是 1 我放行了 0x14000022230 2 ========我是 2 我放行了 0x140000222a0 3 ========我是 3 我放行了 0x14000022310 4 ========我是 4 我放行了 0x14000022380 5 ========我是 5 我放行了 0x140000223f0 6 ========我是 6 我放行了 0x14000022460 7 ========我是 7 我放行了 0x140000224d0 8 ========我是 8 我放行了 0x14000022540 9 ========我是 9 我放行了 0x140000225b0 10 |