Golang并发模式--扇入、扇出

扇入扇出

扇入扇出和pipeline的最大区在于,管线是串行的,但是扇入扇出是并行的。并行是指,一个管线可以接收其它多个数据源的输入,前提是管线对于多个数据源的输入顺序是不敏感的。

一个扇入扇出模块示例图如下:

输入管线1
输入管线2
输入管线3
输出管线
模块A1
扇入扇出模块
模块A2
模块A3
接收器

给出代码示例:

package main
import (
    "fmt"
    "math/rand"
    "runtime"
    "sync"
    "time"
)
func main() {
    fanIn := func(done <-chan interface{}, channels ...<-chan interface{}) <-chan interface{} {
        multiplexedStream := make(chan interface{})
        var wg sync.WaitGroup
        multiplex := func(ch <-chan interface{}) { // 并发输入模块
            defer wg.Done()
            for i := range ch {
                select {
                case <-done:
                    return
                case multiplexedStream <- i:
                }
            }
        }
        wg.Add(len(channels)) // 启动扇入
        for _, c := range channels {
            go multiplex(c)
        }
        go func() { // 所有输入都结束时,扇出管线
            wg.Wait()
            close(multiplexedStream)
        }()
        return multiplexedStream
    }
    generator := func(done <-chan interface{}) <-chan interface{} {
        genCh := make(chan interface{})
        go func() {
            defer close(genCh)
            for {
                select {
                case <-done:
                    return
                case genCh <- rand.Intn(100000):
                    t := rand.Intn(5) + 1 // 模拟工作过程
                    time.Sleep(time.Second * time.Duration(t))
                }
            }
        }()
        return genCh
    }
    take := func(done <-chan interface{}, valueStream <-chan interface{}, n int) <-chan interface{} {
        takeStream := make(chan interface{})
        go func() {
            defer close(takeStream)
            for i := 0; i < n; i++ {
                select {
                case <-done:
                    return
                case n := <-valueStream:
                    takeStream <- n
                }
            }
        }()
        return takeStream
    }
    done := make(chan interface{})
    defer close(done)
    num := runtime.NumCPU()
    chs := make([]<-chan interface{}, num)
    for i := 0; i < num; i++ {
        chs[i] = generator(done)
    }
    for n := range take(done, fanIn(done, chs...), 20) {
        fmt.Printf("%v ", n)
    }
    fmt.Println("")
}

管线的核心思想在于,每个单独的输入都有一个单独goroutine处理,并写入同一个数据源。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值