管线
管线的作用类似于linux的管道,我们利用channel把数据一级级的传递,最终获取数据的结果。管线适用于流处理的方式,而非批处理;流处理可以实时的获取数据。
给出最基础的管线示例,串联加法器和乘法器的管线。
我们使用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)
}
}