Golang并发模式--管线

管线

管线的作用类似于linux的管道,我们利用channel把数据一级级的传递,最终获取数据的结果。管线适用于流处理的方式,而非批处理;流处理可以实时的获取数据。

给出最基础的管线示例,串联加法器和乘法器的管线。

管线1
管线2
管线3
数据生成器
加法器B
乘法器
数据获取器

我们使用channel来表示图中的管线。给出代码示例:

package main

import (
    "fmt"
    "math/rand"
    "time"
)

func main() {
    rand.Seed(time.Now().UTC().UnixNano())

    generator := func(done <-chan interface{}) <-chan int {
        genChan := make(chan int)  // 管线1
        go func() {
            defer close(genChan)
            for {
                select {
                case <-done:
                    return
                case genChan <- rand.Intn(100):
                    time.Sleep(time.Second * time.Duration(rand.Intn(3) + 1))
                }
            }
        }()
        return genChan
    }

    adder := func(done <-chan interface{}, intChan <-chan int, factor int) <-chan int {
        addChan := make(chan int)  // 管线2
        go func() {
            defer close(addChan)
            for n := range intChan {
                select {
                case <-done:
                    return
                case addChan <- (n + factor):
                }
            }
        }()
        return addChan
    }

    multiplier := func(done <-chan interface{}, addChan <-chan int, factor int) <-chan int {
        mulChan := make(chan int)  // 管线3
        go func() {
            defer close(mulChan)
            for n := range addChan {
                select {
                case <-done:
                    return
                case mulChan <- (n * factor):
                }
            }
        }()
        return mulChan
    }

    done := make(chan interface{})
    res := multiplier(done, adder(done, generator(done), 3), 2)
    st := time.Now()
    since := time.Second * 10
    for n := range res {
        if time.Since(st) > since {
            close(done)
            fmt.Println("\nclose pipeline")
            break
        } else {
            fmt.Printf("%v ", n)
        }
    }
    fmt.Println("exit")
}

这种方式不太适用于并发的情况,因为管线内部是串行的,如果有某些处理单元运行慢,则整体速度慢。

常用的生成器

repeat生成器

该生成器用于连续产生一组相同的数据,给出代码示例:


package main
import "fmt"
func main() {
    repeat := func(done <-chan interface{}, values ...interface{}) <-chan interface{} {
        valueStream := make(chan interface{})
        go func() {
            defer close(valueStream)
            for {  // 无限循环产生数据
                for _, v := range values {  // 这里内部遍历
                    select {
                    case <-done:
                        return
                    case valueStream <- v:
                    }
                }
            }
        }()
        return valueStream
    }
    take := func(done <-chan interface{}, valueStream <-chan interface{}, num int) <-chan interface{} {
        takeStream := make(chan interface{})
        go func() {
            defer close(takeStream)
            for i := 0; i < num; i ++ {  // 获取批次数据
                select {
                case <-done:
                    return
                case n := <-valueStream:
                    takeStream <- n
                }
            }
        }()
        return takeStream
    }
    done := make(chan interface{})
    defer close(done)
    for num := range take(done, repeat(done, 1, 3, 5, 7, 9), 10) {
        fmt.Printf("%d ", num)
    }
    fmt.Println("")
}
// 1 3 5 7 9 1 3 5 7 9 

repeatFn生成器

该生成器可以调用外部函数,完成循环重复生成的功能。代码如下:


package main
import (
    "fmt"
    "math/rand"
)
func main() {
    myFn := func() interface{} { return rand.Intn(10000000) }  // 生成器函数
    repeatFn := func(done <-chan interface{}, fn func() interface{}) <-chan interface{} {
        valueStream := make(chan interface{})
        go func() {
            defer close(valueStream)
            for {
                select {
                case <-done:
                    return
                case valueStream <- fn():
                }
            }
        }()
        return valueStream
    }
    take := func(done <-chan interface{}, valueStream <-chan interface{}, n int) <-chan interface{} {
        takeStream := make(chan interface{})
        go func() {
            for i := 0; i < n; i++ {
                select {
                case <-done:
                    return
                case num := <-valueStream:
                    takeStream <- num
                }
            }
        }()
        return takeStream
    }
    done := make(chan interface{})
    defer close(done)
    stream := take(done, repeatFn(done, myFn), 10)
    for n := range stream {
        fmt.Println(n)
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值