gozero mapreduce源码分析和简单实现

Mapreduce

Mapreduce是一种分布式并行编程模型,在一个函数或者一次接口调用中会出现大量的计算或者大量的调用第三方接口的情况。这个时候就可以使用Mapreduce这种变成模型,让大量的计算在一台或者多台机器上处理,最终汇总到一起输出结果。

gozero中的Mapreduce

gozero是一个最近比较流行的go微服务框架,但是在这个库中也有一些比较有意思和好用的类库,我们可以单独引用,就比如其中的Mapreduce
官方是这么说的:在实际的业务场景中我们常常需要从不同的 rpc 服务中获取相应属性来组装成复杂对象。如果是串行调用的话响应时间会随着 rpc 调用次数呈线性增长,所以我们要优化性能一般会将串行改并行。
我们知道如果自己实现一套并行的模式还是比较麻烦的,gozero Mapreduce就可以帮助我们非常容易的实现这样的效果。让我们重点关注自己的业务逻辑的实现。

简单使用

这里需要提一下的时,gozero中还提供了线程数量的控制。可以让你自己控制并行处理的线程数,以免过多的线程对服务器造成过大的消耗。同时我们也可以传入自己的context来控制整个方法的超时和取消逻辑。这些都封装在类库中,不需要我们去操心。只需要传递对的参数就可以了。
下面就是一个比较简单的时候,读取一个数组并行加上“:1”最终输入改变后的数组对象。

package main

import (
    "context"
    "fmt"
    "github.com/zeromicro/go-zero/core/mr"
    "time"
)

func main() {
    //要处理的数据
    uid := []string{"a", "b", "c", "d", "e", "f"}
    //传递数据的逻辑
    generateFunc := func(source chan<- interface{}) {
        for _, v := range uid {
            source <- v
            fmt.Println("source:", v)
        }
    }

    // 处理数据的逻辑
    mapFunc := func(item interface{}, writer mr.Writer, cancel func(err error)) {
        tmp := item.(string) + ":1"
        writer.Write(tmp)
        fmt.Println("item:", item)
    }

    // 合并的数据逻辑
    reducerFunc := func(pipe <-chan interface{}, writer mr.Writer, cancel func(err error)) {
        var uid []string
        for v := range pipe {
            uid = append(uid, v.(string))
            fmt.Println("pipe:", uid)
        }
        writer.Write(uid)
    }

    // 开始并发处理数据
    // 超时时间
    ctx, cl := context.WithTimeout(context.Background(), time.Second*3)
    res, err := mr.MapReduce(generateFunc, mapFunc, reducerFunc, mr.WithContext(ctx))
    //开启现成控制超时,如果超时则调用cl方法停止所有携程
    go func() {
        time.Sleep(time.Second * 2)
        fmt.Println("cl")
        cl()
    }()
    fmt.Println(res, err)
}

源码分析

首先我们先看下一整个函数的流程图,这个流程图是我自己的理解,如果有不对的地方请大家在评论区讨论。
gozero mapreduce源码分析和简单实现_第1张图片

你可能感兴趣的:(gomapreduce源码分析)