標籤:java master-worker模式
Master-Worker模式簡介
Master-Worker模式是非常經典的常用的一個並行計算模式,它的核心思想是2類進程協作工作:Master進程和Worker進程。Master負責接收用戶端請求,分配任務;Worker負責具體處理任務。當各個Worker處理完任務後,統一將結果返回給Master,由Master進行整理和總結。其好處是能夠將一個大JOB分解成若干小JOB,並存執行,從而提高系統的輸送量。比如流行的Web Server,如Nginx,Apache HTTP都存在這種Master-Worker工作模式;離線分散式運算架構Hadoop的JobTracker和TaskTracker,即時資料流計算架構Strom的Nimbus和Supervisor都涉及到這種思想。那麼下面我們來具體分析下Java Master-Worker模式的實現。
Master-Worker模式分析
650) this.width=650;" src="http://s2.51cto.com/wyfs02/M02/8B/12/wKiom1hDkfzB-5wbAAArs5hrPOc274.png" title="搜狗_2016-12-04_11-48-34.png" alt="wKiom1hDkfzB-5wbAAArs5hrPOc274.png" />
我們重點分析下Master,Worker這2個角色。
Master
Master需要接受Client端提交過來的任務Task,而且還得將Task分配給Worker進行處理,因此Master需要一個儲存來存放Task。那麼採用哪種儲存集合呢?首先來說,需要支援並發的集合類,因為多個Worker間可能存在任務競爭,因此我們需要考慮java.util.concurrent包下的集合。這裡可以考慮採用非阻塞的ConcurrentLinkedQueue。
Master需要清楚的知道各個Woker的基本資料,如是否各個Worker都運行完畢,因此Master端需要儲存Worker的資訊,可以採用Map儲存。
由於最後各個Worker都會上報運行結果,Master端需要有一個儲存結果的Map,可以採用支援並發的ConcurrentHashMap。
Worker
Worker需要持有Master端的任務Task集合的引用,因為Worker需要從裡面拿取Task。
同上,Worker需要持有Master端的儲存結果的引用。
綜上,我們可以得到如下:
650) this.width=650;" src="http://s1.51cto.com/wyfs02/M00/8B/0F/wKioL1hDlqHwZeM3AABZMBWVf3Q051.png" title="搜狗_2016-12-04_12-08-48.png" alt="wKioL1hDlqHwZeM3AABZMBWVf3Q051.png" />
我們可以進一步細化,Master/Worker應該提供什麼操作?
Master:
通過構造方法以初始化workers
應該提供submit(Task)方法接受Client端提交過來的任務
start()讓workers開始處理任務
提供isComplete()判斷各個worker的狀態,是否都處理完畢
提供getResult()給用戶端返回結果
Worker:
Worker本質上就是Runnable,提供run()
負責處理商務邏輯的handle()
Java Master-Worker代碼實現
650) this.width=650;" src="http://s2.51cto.com/wyfs02/M02/8B/13/wKiom1hDxaDg3Zb_AAAJ9yFjHPc824.png" title="搜狗_2016-12-04_15-32-25.png" alt="wKiom1hDxaDg3Zb_AAAJ9yFjHPc824.png" />
Task
public class Task { private long id; private String name; public Task(long id, String name) { this.id = id; this.name = name; } public long getId() { return id; } public void setId(long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; }}
Worker
public class Worker implements Runnable { private long id; private String name; private ConcurrentLinkedQueue<Task> workQueue; private ConcurrentHashMap<Long,Object> results; public void setWorkQueue(ConcurrentLinkedQueue<Task> workQueue) { this.workQueue = workQueue; } public void setResults(ConcurrentHashMap<Long, Object> results) { this.results = results; } public Worker(long id, String name) { this.id = id; this.name = name; } @Override public void run() { while(true){ Task task = workQueue.poll(); if(task == null){ break; } long start = System.currentTimeMillis(); long result = handle(task); this.results.put(task.getId(),result); System.out.println(this.name + " handle " + task.getName() + " success . result is " + result + " cost time : " + (System.currentTimeMillis() - start)); } } /** * 負責處理具體商務邏輯 * @param task * @return */ private long handle(Task task) { //這裡只是類比下,在真實環境也許是查詢資料庫,也許是查緩衝等 try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } return new Random().nextLong(); }}
Master
public class Master { private ConcurrentLinkedQueue<Task> workQueue = new ConcurrentLinkedQueue<Task>(); private Map<Long,Thread> workers = new HashMap<Long, Thread>(); private ConcurrentHashMap<Long,Object> results = new ConcurrentHashMap<Long, Object>(); public Master(int num){ for(int i = 0 ; i < num ; i++){ Worker worker = new Worker(i,"worker-" + i); worker.setResults(results); worker.setWorkQueue(workQueue); workers.put(Long.valueOf(i),new Thread(worker)); } } public void submit(Task task){ workQueue.add(task); } public void start(){ for (Map.Entry<Long,Thread> entry : workers.entrySet()){ entry.getValue().start(); } } public boolean isComlepte(){ for(Map.Entry<Long,Thread> entry : workers.entrySet()){ if(entry.getValue().getState() != Thread.State.TERMINATED){ return false; } } return true; } public long getSumResult(){ long value = 0; for(Map.Entry<Long,Object> entry : results.entrySet()){ value = value + (Long)entry.getValue(); } return value; }}
Main
public class Main { public static void main(String[] args) { Master master = new Master(10); for(int i = 0 ; i < 10 ; i++){ Task task = new Task(i,"task-" + i); master.submit(task); } long start = System.currentTimeMillis(); master.start(); while(true){ if(master.isComlepte()){ System.out.println("sum result is " + master.getSumResult() + " . cost time : " + (System.currentTimeMillis() - start)); break; } } }}
運行結果
650) this.width=650;" src="http://s5.51cto.com/wyfs02/M02/8B/0F/wKioL1hDxjzwX2K2AACBfC_nvdY147.png" title="搜狗_2016-12-04_15-35-02.png" alt="wKioL1hDxjzwX2K2AACBfC_nvdY147.png" />
總結
在單線程的時候,處理一個Task需要500ms,那麼處理10個Task需要5S,如果採用Master-Worker這種並行模型,可以大大縮短計算處理時間。
本文出自 “學海無涯 心境無限” 部落格,請務必保留此出處http://zhangfengzhe.blog.51cto.com/8855103/1879323
Java Master-Worker模式實現