并行模式之Master-Worker模式

一)、Master-Worker模式

作用: 将一个大任务分解成若干个小任务,分发给多个子线程执行。

注: 将大任务分解成小任务,小任务的实现逻辑要相同。

二)、Master-Worker模式的结构

Master-Worker的核心思想:由Master进程和Worker进程实现。

1)、Master进程:

接收和分配任务,整合最终的处理结果。

内部结构组成:

1.Worker进程队列

作用:执行Master分配的任务,开启多线程处理数据。

2.子任务队列

 作用:接收任务。

3.子结果集

 作用:整合多个线程的最终处理结果。

注:Master进程分配任务后会立即返回,不会等待系统全部处理完返回,处理过

     程是异步的,client不会出现等待状态。

2)、Worker进程

实现Runable接口,定义一个handle()方法,在方法里实现小任务的业务逻辑,在run()方法中调用handle()方法

内部结构组成:

1.子任务队列

作用:接收Master分配的任务。

2.结果集队列

 作用:将处理的结果返给Master

3.handle()方法

作用:定义小任务的业务逻辑。

注:所有的Wroker对象共享Master的Worker队列,和结果集.

三)、Master-Worker的代码实现

使用Master-Worker模式实现 :

计算 1~100的立方和( 1^3 + 2^3 + ... + 100^3 )

思路:将计算任务分解为100个小任务,每个子任务计算单独的立方和,最后将计

         算结果返回给master。

Master类:

/**
* Master类:
* 内部维护了一个Worker进程队列、任务队列、结果集
*/
public class Master {
/**
* 任务队列, ConcurrentLinkedDeque: 基于链表的并发队列
*/
protected Queue workerQueue = new ConcurrentLinkedDeque(); /**
* Worker进程队列
*/
Map<String, Thread> threadMap = new HashMap<>(); /**
* 结果集
*/
Map<String, Object> resultMap = new HashMap<>(); /**
* Master的构造,需要一个进程对象和进程数量
*/
public Master(Worker worker, int countWorker){
//将master的workerQueue和resultMap和Worker关联
worker.setWorkerQueue(workerQueue);
worker.setResultMap(resultMap);
//根据需要的进程数量,创建进程
for(int i = 0; i < countWorker; i++){
//Integer.toString(i)为线程的名字
threadMap.put(Integer.toString(i), new Thread(worker,Integer.toString(i)));
}
} /**
* master进程提交任务
*/
public void submit(Object input){
workerQueue.add(input);
} /**
* master分配任务,执行任务,开启多线程
*/
public void execute(){
for(Map.Entry<String,Thread> entry : threadMap.entrySet()){
entry.getValue().start(); }
} /**
* 判断是否所有的子任务都结束了
*/
public boolean isComplete(){
//判断worker进程的状态是否都等于终止状态
for(Map.Entry<String,Thread> entry : threadMap.entrySet()){
if(entry.getValue().getState() != Thread.State.TERMINATED){
return false;
}
}
return true;
} public Queue getWorkerQueue() {
return workerQueue;
} public void setWorkerQueue(Queue workerQueue) {
this.workerQueue = workerQueue;
} public Map<String, Thread> getThreadMap() {
return threadMap;
} public void setThreadMap(Map<String, Thread> threadMap) {
this.threadMap = threadMap;
} public Map<String, Object> getResultMap() {
return resultMap;
} public void setResultMap(Map<String, Object> resultMap) {
this.resultMap = resultMap;
}
}

Worker类:实现Runable接口,定义handle()方法,在run()中调用handle()

/**
* Worker类:
* 小任务的逻辑实现类
*/
public class Worker implements Runnable{
/**
* 接收master的workerQueue,用于开启线程处理多个小任务
*/
protected Queue workerQueue; /**
* 接收master的resultMap,将各个小任务的处理结果返回给Master
*/
protected Map<String, Object> resultMap; /**
* 小线程的具体逻辑,接收任务并处理任务
* 参数: input,分解的小任务
*/
public Object handle(Object input){
return input;
} /**
* 从任务列表中获取任务,调用handle()方法,执行任务
*/
@Override
public void run() {
while(true){
//获取任务列表的任务
Object input = workerQueue.poll();
//判断任务列表是否还有任务,若没有,则终止线程。
if(input == null){
break;
}
//有任务,调用handle()方法,执行任务
Object result = handle(input);
//将结果放在master的resultMap中
resultMap.put(Integer.toString(input.hashCode()),result);
}
} public Queue getWorkerQueue() {
return workerQueue;
} public void setWorkerQueue(Queue workerQueue) {
this.workerQueue = workerQueue;
} public Map<String, Object> getResultMap() {
return resultMap;
} public void setResultMap(Map<String, Object> resultMap) {
this.resultMap = resultMap;
} }

PlushWorker类:继承了Worker类,重写handle()方法,定义任务的处理逻辑

**
* 继承Worker类,定义handle()的业务逻辑
*/
public class PlushWorker extends Worker{
/**
* 对任务进行处理,在run()方法中调用该方法
* @param input
* @return
*/
@Override
public Object handle(Object input){
int i = (Integer)input;
return i * i * i;
}
}

main类:使用master计算 1~100的立方和( 1^3 + 2^3 + ... + 100^3 )

/**
* 使用Master-Worker模式实现 :
* 计算 1~100的立方和( 1^3 + 2^3 + ... + 100^3 )
* 1.将计算任务分解为100个小任务,每个子任务计算单独的立方和,最后将计算结果返回给master
*/
public class CubicAndCalculate {
public static void main(String[] args) {
//创建Master对象,开启五个线程对任务进行处理
Master master = new Master(new PlushWorker(), 5);
//将大任务分解成100个小任务
for(int i = 1; i <= 100; i++){
master.submit(i);
}
//开启多线程,并发的处理多个小任务
master.execute();
//master可以不用等全部的任务执行完便可以获取任务的执行结果
Map<String, Object> resultMap = master.getResultMap();
Integer re = 0;
//加入两个判断是因为,每取出一个resultMap中的数据,都要对该数据删除,若消费resultMap的速度比生成的快,可通过判断任务线程是否执行完毕来控制数据的获取
while(resultMap.size() > 0 || !master.isComplete()){
//获取map的所有键
Set<String> set = resultMap.keySet();
String key = null;
for(String k : set){
key = k;
break;
}
Integer i = null;
//判断map中是否有数据,若key值为null,就不进行获取值操作
if(key != null){
i = (Integer) resultMap.get(key);
}
//如果key存在,i !=null,则对返回的部分的任务的立方和进行累加,并移除resultMap中对应的项
if(i != null){
re += i;
resultMap.remove(key);
}
}
System.out.println(re);
}
}

结果:

25502500

并行模式之Master-Worker模式的更多相关文章

  1. Master和worker模式

    让和hadoop的设计思想是一样的,Master负责分配任务和获取任务的结果,worker是真正处理业务逻辑的. 使用ConcurrentLikedQueue去承载所有的任务,因为会有多个worker ...

  2. Apache常用2种工作模式prefork和worker比较

    Apache两种常用工作模式:prefork和worker. prefork MPM prefork是一个非线程型的.预派生的MPM,使用多个进程,每个进程在某个确定的时间只单独处理一个连接,效率高, ...

  3. Apache的prefork模式和worker模式(转)

    prefork模式这个多路处理模块(MPM)实现了一个非线程型的.预派生的web服务器,它的工作方式类似于Apache 1.3.它适合于没有线程安全库,需要避免线程兼容性问题的系统.它是要求将每个请求 ...

  4. Apache的prefork模式和worker模式

    prefork模式这个多路处理模块(MPM)实现了一个非线程型的.预派生的web服务器,它的工作方式类似于Apache 1.3.它适合于没有线程安全库,需要避免线程兼容性问题的系统.它是要求将每个请求 ...

  5. puppet(5)-master/agent模式

    master/agent模式的工作流程 agent每隔固定时长会向master端发送nodename(自己的节点名,节点名至关重要)和 facts ,并且向服务器端请求自己的catalog. mast ...

  6. [PHP] apache在worker模式配置fastcgi使用php-fpm

    1.准备: dpkg -L apache2查看所有安装的apache2的应用 a2query -M查看apache2使用的模式 httpd -l旧版本查看当前apache模式 2.查看apache的进 ...

  7. apache常用的两种工作模式 prefork和worker

    apache作为现今web服务器用的最广泛也是最稳定的开源服务器软件,其工作模式有许多中,目前主要有两种模式:prefork模式和worker模式 一.两种模式 prefork模式: prefork是 ...

  8. jenkins的Master/Slave模式

    一. Master/Slave模式 分担jenkins服务器的压力,任务分配到其它执行机来执行 Master:Jenkins服务器 Slave:执行机(奴隶机).执行Master分配的任务,并返回任务 ...

  9. Ubuntu下配置Apache的Worker模式

    其实Apache本身的并发能力是足够强大的,但是Ubuntu默认安装的是Prefork模式下的Apache.所以导致很多人后面盲目的去 安装lighttpd或者nginx一类替代软件.但是这类软件有一 ...

  10. Puppet基于Master/Agent模式实现LNMP平台部署

    前言 随着IT行业的迅猛发展,传统的运维方式靠大量人力比较吃力,运维人员面对日益增长的服务器和运维工作,不得不把很多重复的.繁琐的工作利用自动化处理.前期我们介绍了运维自动化工具ansible的简单应 ...

随机推荐

  1. Kafka源码研究--Comsumer获取partition下标

    背景 由于项目上Flink在设置parallel多于1的情况下,job没法正确地获取watermark,所以周末来研究一下一部分,大概已经锁定了原因: 虽然我们的topic只设置了1的partitio ...

  2. vue 代码迁移的坑

    由于开发需要,开发过程中总会遇到由于代码调试.svn/git上传等过程中,总会出现代码迁移文件的需求,很多时候,迁移过后总会出现一些大大小小的问题, 首先,需要迁移文件内有没有系统自动隐藏的文件(例如 ...

  3. PHPStorm 10 配置PHPUnit

    PHPStorm 10 配置PHPUnit PHPUnit的安装 自己用的是Xampp,PHPUnit好像自带不好用. 不说废话: 自己看 According to official site htt ...

  4. Unity事件系统

    # 1.前言Unity中事件/委托有着广泛的应用,本文通过封装一个简易的事件的系统,来统一管理消息的传递.此功能在简易应用或者事件较少的体现不出太好的作用,但是对于事件应用较多时,可以减少脚本之间的耦 ...

  5. fenby C语言

    P1框架 1#include <stdio.h> 2 3int main(){ 4    printf(“C语言我来了”); 5    return 0; 6} P2main()门 P3计 ...

  6. ubuntu18.04 flink-1.9.0 Standalone集群搭建

    集群规划 Master JobManager Standby JobManager Task Manager Zookeeper flink01 √ √ flink02 √ √ flink03 √ √ ...

  7. 痞子衡嵌入式:飞思卡尔i.MX RTyyyy系列MCU硬件那些事(2.2)- 在串行NOR Flash XIP调试原理

    大家好,我是痞子衡,是正经搞技术的痞子.今天痞子衡给大家介绍的是飞思卡尔i.MX RTyyyy系列EVK在串行NOR Flash调试的原理. 本文是i.MXRT硬件那些事系列第二篇的续集,在第二篇首集 ...

  8. jwt token

    1 ,session 认证机制: ,用户登录,传递用户名和密码给客户端 ,服务器进行用户名和密码的校验,如果校验成功,将用户保存到session ,将sessionid通过cookie返回给客服端,客 ...

  9. Vue---mock.js 使用

    mockjs 概述 在我们的生产实际中,后端的接口往往是较晚才会出来,并且还要写接口文档,于是我们的前端的许多开发都要等到接口给我们才能进行,这样对于我们前端来说显得十分的被动,于是有没有可以制造假数 ...

  10. vue2.0 与 vue3.0 配置的区别

    提示:要了解vue2.0与vue3.0区别,首先你要熟悉vue2.0 从最明显最简单的开始 项目目录结构 可以明显的看出来,vue2.0与3.0在目录结构方面,有明显的不同(vue3.0我是安装了cs ...