深入理解[Master-Worker模式]原理与技术

Posted yueshutong

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了深入理解[Master-Worker模式]原理与技术相关的知识,希望对你有一定的参考价值。

Master-Worker模式是常用的并行模式之一。它的核心思想是,系统由两类进程协作工作:Master进程和Worker进程。Master进程负责接收和分配任务,Worker进程负责处理子任务。当各个Worker进程将子任务处理完成后,将结果返回给Master进程,由Master进程做归纳和汇总,从而得到系统的最终结果,其处理过程如图1所示。

技术分享图片

Master-Worker模式的好处,它能够将一个大任务分解成若干个小任务,并且执行,从而提高系统的吞吐量。而对于系统请求者Client来说,任务一旦提交,Master进程会分配任务并立即返回,并不会等待系统全部处理完成后再返回,其处理过程是异步的。因此Client不会出现等待现象。

1.Master-Worker的模式结构

Master-Worker模式是一种使用多线程进行数据结构处理的结构。

Master进程为主要进程,它维护了一个Worker进程队列、子任务队列和子结果集。Worker进程队列中的Worker进程,不停地从任务队列中提取要处理的子任务,并将子任务的处理结果写入结果集。

2.Master-Worker的代码实现

基于以上的思路实现一个简易的master-worker框架。其中Master部分的代码如下:

public class Master {
    //任务队列
    protected Queue<Object> workQuery = new ConcurrentLinkedQueue<Object>();
    //worker进程队列
    protected Map<String, Thread> threadMap = new HashMap<>();
    //子任务处理结果集
    protected Map<String, Object> resultMap = new ConcurrentHashMap<>();

    //是否所有的子任务都结束了
    public boolean isComplete() {
        for (Map.Entry<String, Thread> entry : threadMap.entrySet()) {
            if (entry.getValue().getState()!=Thread.State.TERMINATED){
                return false;
            }
        }
        return true;
    }

    //Master 的构造,需要一个Worker 进程逻辑,和需要的Worker进程数量
    public Master(Worker worker,int countWorker){
        worker.setWorkQueue(workQuery);
        worker.setResultMap(resultMap);
        for (int i = 0; i < countWorker; i++) {
            threadMap.put(Integer.toString(i),new Thread(worker));
        }
    }

    //提交一个任务
    public void submit(Object job){
        workQuery.add(job);
    }

    //返回子任务结果集
    public Map<String,Object> getResultMap(){
        return resultMap;
    }

    //开始运行所有的worker进程,进行处理
    public void  execute(){
        for (Map.Entry<String,Thread> entry : threadMap.entrySet()){
            entry.getValue().start();
        }
    }

}

对应的Worker进程的代码实现:

public class Worker implements Runnable {
    //任务队列,用于取得子任务
    protected Queue<Object> workQueue;
    //子任务处理结果集
    protected Map<String, Object> resultMap;

    public void setWorkQueue(Queue<Object> workQueue) {
        this.workQueue = workQueue;
    }

    public void setResultMap(Map<String, Object> resultMap) {
        this.resultMap = resultMap;
    }

    //子任务处理的逻辑,在子类中实现具体逻辑
    public Object handle(Object input) {
        return input;
    }

    @Override
    public void run() {
        while (true) {
            //获取子任务
            Object input = workQueue.poll();
            if (input == null) {
                break;
            }
            //处理子任务
            Object re = handle(input);
            //将处理结果写入结果集
            resultMap.put(Integer.toString(input.hashCode()), re);
        }
    }
}

以上两段代码已经展示了Master-Worker框架的全貌。应用程序通过重载 Worker.handle() 方法实现应用层逻辑。

例如,要实现计算1+2+..+100的结果,代码如下:

public class PlusWorker extends Worker {

    @Override
    public Object handle(Object input) {
        Integer i = (Integer) input;
        return i+1;
    }

    public static void main(String[] args) {
        Master master = new Master(new PlusWorker(), 5);
        for (int i = 0; i < 100; i++) {
            master.submit(i); //提交一百个子任务
        }
        master.execute(); //开始计算
        int re = 0;
        Map<String, Object> resultMap = master.getResultMap();
        while (resultMap.size() > 0 || !master.isComplete()) {
            Set<String> keys = resultMap.keySet();
            String key = null;
            for (String k : keys) {
                key = k;
                break;
            }
            Integer i = null;
            if (key != null) {
                i = (Integer) resultMap.get(key);   //从结果集中获取结果
            }
            if (i != null) {
                re += i;        //最终结果
            }
            if (key != null) {
                resultMap.remove(key);      //移除已经被计算过的项
            }
        }
        System.out.println("result: " + re);
    }

}

运行结果:

result: 5050

在应用层代码中,创建了5个Worker工作进程和Worker工作实例PlusWorker。在提交了100个子任务后,便开始子任务的计算。这些子任务中,由生成的5个Worker进程共同完成。Master并不等待所有的Worker执行完毕,就开始访问子结果集进行最终结果的计算,直到子结果集中所有的数据都被处理,并且5个活跃的Worker进程全部终止,才给出最终计算结果。

Master-Worker模式是一种将串行任务并行化的方法,被分解的子任务在系统中可以被并行处理。同时,如果有需要,Master进程不需要等待所有子任务都完成计算,就可以根据已有的部分结果集计算最终结果。

3.Amino框架提供的Master-Worker模式

在Amino框架中为Master-Worker模式提供了较为完善的实现和便捷的操作接口。Amino实现了两套Master-Worker实现:一种是静态的Master-Worker实现,另一种是动态实现。

静态实现不允许在任务开始时添加新的子任务,而动态的Master-Worker允许在任务执行过程中,由Master或Worker添加新的子任务。

在Amino框架中,MasterWorkerFactory.newStatic(new Pow3(),20)用于创建静态的Master-Worker模式,

第二个参数为Worker线程数,第一个参数为执行的任务类,该类需实现Doable<Integer,Integer>接口,该接口泛型的第一个类型为任务方法的参数类型,第二个类型为方法返回类型。MasterWorkerFactory.newDynamic(new Pow3Dyn())用于创建动态的Master-Worker模式,其中参数为实现DynamicWorker接口的实例。

submit()方法用于提交应用层任务,execute()方法将执行所有任务。

Amino框架需要自行下载,下载地址:https://sourceforge.net/projects/amino-cbbs/files/cbbs/0.5.3/,找到cbbs-java-bin-0.5.3.tar.gz 下载即可。

下面用Amino框架演示1+2+..+100的完整示例。

public class Pow3 implements Doable<Integer,Integer> {
    @Override
    public Integer run(Integer input) {
        //业务逻辑
        return input;
    }
}
public class Pow3Dyn implements DynamicWorker<Integer,Integer> {
    @Override
    public Integer run(Integer integer, WorkQueue<Integer> workQueue) {
        //业务逻辑
        return integer;
    }
}
public class AminoDemo {

    /
     * Amino 框架提供开箱即用的Master-Worker模式
     * 其它用法参考API文档
     */
    public static void main(String[] args) {
        new AminoDemo().testDynamic();
        new AminoDemo().testStatic();
    }

    /
     * 静态模式,不允许在任务开始后添加新的任务
     */
    public void testStatic(){
        MasterWorker<Integer,Integer> mw = MasterWorkerFactory.newStatic(new Pow3(),20);//静态模式,可指定线程数
        List<MasterWorker.ResultKey> keyList = new Vector<>();
        for (int i = 1; i <= 100; i++) {
            keyList.add(mw.submit(i)); //传参并调度任务,key用于取得任务结果
        }
        mw.execute();//执行所有任务
        int re = 0;
        while (keyList.size()> 0){ //不等待全部执行完成,就开始求和
            MasterWorker.ResultKey k = keyList.get(0);
            Integer i = mw.result(k); //由Key取得一个任务结果
            if (i!=null){
                re+=i;
                keyList.remove(0); //累加完成后
            }
        }
        System.out.println("result:"+re);
        mw.shutdown();//关闭master-worker,释放资源
    }

    /
     * 动态模式,可在开始执行任务后继续添加任务
     */
    public void testDynamic(){
        MasterWorker<Integer,Integer> mw = MasterWorkerFactory.newDynamic(new Pow3Dyn());//动态模式,可指定线程数
        List<MasterWorker.ResultKey> keyList = new Vector<>();
        for (int i = 1; i < 50; i++) {
            keyList.add(mw.submit(i)); //传参并调度任务,key用于取得任务结果
        }
        mw.execute();
        for (int i = 50; i <= 100; i++) {
            keyList.add(mw.submit(i)); //传参并调度任务,key用于取得任务结果
        }
        int re = 0;
        while (keyList.size()> 0){
            MasterWorker.ResultKey k = keyList.get(0);
            Integer i = mw.result(k); //由Key取得一个任务结果
            if (i!=null){
                re+=i;
                keyList.remove(0); //累加完成后
            }
        }
        System.out.println("result:"+re);
        mw.shutdown();
    }

}

运行结果:

result:5050
result:5050

MasterWorker类的方法摘要,其它请自行下载API文档。cbbs-java-apidocs-0.5.3.tar.gz

方法摘要
boolean execute() Begin processing of the work items submitted.
boolean execute(long timeout, java.util.concurrent.TimeUnit unit) Begin processing of the work items submitted.
void finished() Indicate to the master/worker that there is not more work coming.
java.util.Collection<T> getAllResults() Obtain all of the results from the processing work items.
boolean isCompleted() Poll an executing master/worker for completion.
boolean isStatic() Determine if a master/worker is static.
int numWorkers() Get the number of active workers.
T result(MasterWorker.ResultKey k) Obtain the results from the processing of a work item.
void shutdown() Shutdown the master/worker.
MasterWorker.ResultKey submit(S w) Submit a work item for processing.
MasterWorker.ResultKey submit(S w, long timeout, java.util.concurrent.TimeUnit unit) Submit a work item for processing and block until it is either submitted successfully or the specified timeout period has expired.
boolean waitForCompletion() Wait until all workers have completed.
boolean waitForCompletion(long timeout, java.util.concurrent.TimeUnit unit) Wait until all workers have completed or the specified timeout period expires.

以上是关于深入理解[Master-Worker模式]原理与技术的主要内容,如果未能解决你的问题,请参考以下文章

深入理解代理模式原理与技术

深入理解[代理模式]原理与技术

Java Thread系列Master-Worker模式

并行设计模式-- Master-Worker模式

深入理解AQS

深入理解VMware虚拟机网络通信原理