开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 19 天,点击查看活动详情
Pipeline
Pipeline是一种常见的设计模式,用于将多个处理步骤连接起来,以便数据可以通过它们进行转换和处理。
在Pipeline模式中,数据从一个处理步骤流经下一个处理步骤,以此类推,直到到达最终的处理步骤。每个处理步骤只处理数据的一部分,然后将其传递给下一个步骤。
这种模式的好处在于,它可以让我们将复杂的处理任务分解成一系列相对简单的任务,从而更容易进行维护和调试。此外,由于每个步骤只处理数据的一部分,因此可以并行处理多个步骤,从而加速整个处理过程。
在实际应用中,Pipeline模式广泛应用于数据处理、计算机视觉、自然语言处理等领域。例如,在机器学习中,我们可以将数据预处理、特征提取、模型训练等步骤组合在一起形成Pipeline,以进行模型训练和推理。在图像处理中,我们可以将图像分割、特征提取、分类等步骤组合在一起形成Pipeline,以进行图像识别和分类。
Pepeline 实现
定义基本pipeline节点的接口filter相当于一次计算,
type Request interface{}
type Response interface{}
type Pipe interface {
Process(data Request) (Response, error)
}
定义pipeline组装器,组装多任务成pipeline并可调用。
func NewPipeline(name string, filters ...Pipe) *Pipeline {
return &Pipeline{
Name: name,
Pipes: &filters,
}
}
type Pipeline struct {
Name string
Pipes *[]Pipe
}
func (p *Pipeline) Process(data Request) (Response, error) {
var ret interface{}
var err error
for _, pipe := range *p.Pipes {
ret, err = pipe.Process(data)
if err != nil {
return ret, err
}
data = ret
}
return ret, err
}
Pipeline调用
例如我们要实现一个对字符串的操作,先分割,再各自转为int,再求和返回结果:
- 定义分割器
var SplitPipeWrongFormatError = errors.New("input data should be string")
type SplitPipe struct {
delimiter string
}
func NewSplitPipe(delimiter string) *SplitPipe {
return &SplitPipe{delimiter}
}
func (sf *SplitPipe) Process(data Request) (Response, error) {
str, ok := data.(string) //检查数据格式/类型,是否可以处理
if !ok {
return nil, SplitPipeWrongFormatError
}
parts := strings.Split(str, sf.delimiter)
return parts, nil
}
- 定义类型转换器
var ToIntPipeWrongFormatError = errors.New("input data should be []string")
type ToIntPipe struct {
}
func NewToIntPipe() *ToIntPipe {
return &ToIntPipe{}
}
func (tif *ToIntPipe) Process(data Request) (Response, error) {
parts, ok := data.([]string)
if !ok {
return nil, ToIntPipeWrongFormatError
}
ret := []int{}
for _, part := range parts {
s, err := strconv.Atoi(part)
if err != nil {
return nil, err
}
ret = append(ret, s)
}
return ret, nil
}
- 定义求和器
var SumPipeWrongFormatError = errors.New("input data should be []int")
type SumPipe struct {
}
func NewSumPipe() *SumPipe {
return &SumPipe{}
}
func (sf *SumPipe) Process(data Request) (Response, error) {
elems, ok := data.([]int)
if !ok {
return nil, SumPipeWrongFormatError
}
ret := 0
for _, elem := range elems {
ret += elem
}
return ret, nil
}
- 初始化,拼接,调用
func TestStraightPipeline(t *testing.T) {
spliter := NewSplitPipe(",")
converter := NewToIntPipe()
sum := NewSumPipe()
sp := NewPipeline("p1", spliter, converter, sum)
ret, err := sp.Process("1,2,3")
if err != nil {
t.Fatal(err)
}
if ret != 6 {
t.Fatalf("The expected is 6, but the actual is %d", ret)
}
}