高級并發(fā):實(shí)現(xiàn) Or-Channel 模式
在實(shí)際業(yè)務(wù)中,某個(gè) goroutine 常常依賴多個(gè)并行任務(wù)的結(jié)果。例如,同時(shí)向多臺服務(wù)器請求同一份數(shù)據(jù),只要任意一臺返回成功即可取消其余請求。此時(shí),需要合并多個(gè)完成(done)通道,實(shí)現(xiàn)“只要任一任務(wù)完成即可整體結(jié)束”的邏輯。
本文通過實(shí)現(xiàn)一個(gè)通用的 or 函數(shù)來演示這一模式,并展示其在動態(tài)通道數(shù)量場景下的優(yōu)雅用法。

問題描述:合并多個(gè)完成通道
目標(biāo)函數(shù)簽名如下:
var or func(doneChannels ...<-chan interface{}) <-chan interface{}or 接收任意數(shù)量的只讀通道,并返回一個(gè)新的只讀通道。當(dāng)任一輸入通道關(guān)閉時(shí),返回的通道立即關(guān)閉。
實(shí)現(xiàn) or 函數(shù)
零或一個(gè)通道:
or = func(doneChannels ...<-chan interface{}) <-chan interface{} {
switch len(doneChannels) {
case 0:
return nil // 無通道可監(jiān)聽
case 1:
return doneChannels[0] // 直接返回原通道
}
return nil
}兩個(gè)通道:
or = func(doneChannels ...<-chan interface{}) <-chan interface{} {
if len(doneChannels) < 2 {
return or(doneChannels...)
}
done := make(chan interface{})
go func() {
defer close(done)
select {
case <-doneChannels[0]:
case <-doneChannels[1]:
}
}()
return done
}任意數(shù)量通道(遞歸實(shí)現(xiàn)):
or = func(doneChannels ...<-chan interface{}) <-chan interface{} {
switch len(doneChannels) {
case 0:
return nil
case 1:
return doneChannels[0]
}
done := make(chan interface{})
go func() {
defer close(done)
select {
case <-doneChannels[0]:
case <-doneChannels[1]:
case <-or(doneChannels[2:]...): // 遞歸合并剩余通道
}
}()
return done
}遞歸方案可處理任意數(shù)量的通道,避免手動編寫嵌套 select 造成的可讀性下降。
使用示例
sig := func(after time.Duration) <-chan interface{} {
c := make(chan interface{})
go func() {
defer close(c)
time.Sleep(after)
}()
return c
}
start := time.Now()
<-or(
sig(2*time.Hour),
sig(5*time.Minute),
sig(1*time.Second),
sig(1*time.Hour),
sig(1*time.Minute),
)
fmt.Printf("done after %v\n", time.Since(start))輸出示例:
done after 1.002543s無論其余通道需要多長時(shí)間,or 都會在最快完成的通道關(guān)閉后立即返回控制權(quán)。
結(jié)論
or-channel 模式是 Go 并發(fā)編程中處理多源完成信號的利器。通過遞歸實(shí)現(xiàn),可以在不增加復(fù)雜度的前提下支持動態(tài)數(shù)量的通道。這一技巧適用于:
- 聚合超時(shí)或取消信號;
- 構(gòu)建彈性系統(tǒng),快速響應(yīng)最先完成的任務(wù);
- 合并多個(gè)結(jié)果通道的完成事件;
- 合理運(yùn)用該模式,可顯著提升并發(fā)代碼的可讀性與健壯性。































