概述
流水线作业,是多个线程协作,就像加工车间的传送带,每个线程完成一项任务,然后把结果发送给下一个线程,直到所有线程的任务完成,一个“产品”的加工过程就完成了。
通过Go的channel,可以很方便的实现流水线作业。
流水线作业的实现
在linux系统编程中,一般来说流水线作业的线程数是固定的,我们模拟的这个场景,假设有几个固定的goroutine共同协作来完成一个字符串的处理,goroutine之间通过channel来进行数据传递,各个goroutine主要进行的操作如下:
1. 第1个goroutine:一个字符串全部改成小写
2. 第2个:在该字符串前面添加HELLO: 字样
3. 第3个:统计字数,并打印字符串
当然,你可以把这些操作替换成任意你想完成的任务,就可以使用了。
代码实现
package main
import (
"fmt"
"os"
"strings"
"time"
)
//
// 模拟流水线作业:
// 1. 一个字符串全部改成小写
// 2. 在该字符串前面添加HELLO: 字样
// 3. 统计字数,并打印字符串
//
func starter(ch1 chan string) {
for i := 0; i <10; i++ {
v := fmt.Sprintf("HoVer: %d", i)
fmt.Fprintf(os.Stderr, "starter send: %s\n", v)
ch1 <- v
time.Sleep(1e9)
}
}
func lowString(ch1 chan string, ch2 chan string) {
for {
str := <- ch1
res := strings.ToLower(str)
ch2 <- res
}
}
func addString(ch2 chan string, ch3 chan string) {
for {
str := <- ch2
res := fmt.Sprintf("HELLO: %s", str)
ch3 <- res
}
}
func getResult(ch3 chan string) {
for {
v := <- ch3
len := len(v)
fmt.Fprintf(os.Stderr, "len=%d, result=%s\n", len, v)
}
}
func main() {
ch := make(chan string)
go starter(ch)
ch1 := make(chan string)
go lowString(ch, ch1)
ch2 := make(chan string)
go addString(ch1, ch2)
go getResult(ch2)
time.Sleep(100e9)
}
总结
通过channel(容量为1)的数据传递可以很方便的实现流水线的模型,这样每个goroutine就可以只专注于完成自己的那一部分任务,从而把一个复杂的任务分解成相互依赖的小任务来进行处理。