3. 研究方法
3.2 MPI Component
MPI Component 在設計上需考慮到使用者連線問題、Open MPI 程式不能接到立即 啟動,過多任務在同時間執行會大幅影響 Open MPI 運算效能,與在系統設計中提供 的特殊服務等,接下來對其做詳細說明。
Spring Framework 多執行緒設計引入 Guarded Suspension
第二章文獻探討的 Spring Framework 曾提及如何取得 IoC 的屬性參數,但 其範例只適用於單一執行緒情況下,多執行緒設計時如對 Spring 做多次設定檔 的初始化,會產生 bean 已被建立的錯誤,導致系統關閉。其中一種解決方式 為將 Spring 設定檔物件初始化獨立出來設為一個實體,系統執行時先將其初始 化,不同執行緒再利用 getter 方式取得其設定檔物件。但此種方法又產生資料
不確定性的問題,如文獻探討 Guarded Suspension Design Pattern 部分所述,故 採用 Guarded Suspension Design Pattern 概念對 Spring 設定物件檔的 getter 方法 做單一取用的保護,實現方法如圖 3.7。
圖 3.7 SpringConfigTool.java
ServerSocket 引入 Design Pattern 增加處理效能與程式結構的乾淨
MPI Server 使用 Socket 建立連線,一般在開發時若在 Socket Class 內加入 處理邏輯,整個程式碼便會很冗長且不易維護,故引入 Strategy Design Pattern 為服務邏輯另外封裝。要設計多人連線就頇使用執行緒為每一連線做處理,便 是文獻探討中 Thread-Per-Message Design Pattern 的實現。但每當連線建立就必 頇初始化一執行緒如文獻中 Worker Thread Design Pattern 所述,會造成系統資 源多餘的消耗。我們希望連線數量能有最小值與最大值,預先初始化最小值的 執行緒作為 Worker Thread,當有過多的連線需求時在增加執行緒加入 Weoker Thread,這便是 Thread Pool 的一種實現。圖 3.8 示意 MPI Server 內處理連線需 求的實體,Server 接受 Client 的連線需求後交由以 Thread Pool 設計的 Client Workder 負責執行,而真正的處理服務邏輯以 interface 作為接口在另外實作服 務程式實體。
public class SpringConfigTool implements ApplicationContextAware { private static ApplicationContext context = null;
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
context = applicationContext;
}
public synchronized static Object getBean(String beanName) { return context.getBean(beanName);
} }
圖 3.8 MPI Server 連線處理循序圖
由於 MPI 程式如處理大量資料會執行過久導致回應遲緩,故設計 Task Queue 存放 MPI 程式執行的需求,並於存放完成後通知 Client 處理中,實現快 速回應。使用者若欲檢視處理結果,需如上一節所述透過 MPI Manager 查詢。
圖 3.8Task Queue 的處理執行緒由 Task Worker 負責,為 Worker Thread Design Pattern 的實現,不使用 Thread Pool 原因為論文中設計之數量為固定,若過多 MPI 任務被提交,會影響正在處理的 MPI 程式的運算速度。
MPI Dispatch Module 子功能中的 Customer Runner
MPI Dispatch Module 內有個 Customer Runner 子功能,其提供使用論文程 式的開發者可自行加入外部程式對 Package 做有限度的修改。Customer Runner 如何設計,才能在不重新編譯情況下執行外部程式,擷取 Unit Test 裡的設計概 念[34],JAVA 程式語言中有一個 Reflection 的特性,只要系統中設定好 classpath 路徑,便可以取用其編譯好的 class 檔或 library,圖 3.9 範例如何取用外部 com.test.CustomerClass 並執行其 public method,圖 3.10 為 CustomerClass,其 中 private 的 hide method 不會被執行。本研究利用此特性結合 Spring 的 IoC 功
能,只要在外部設定檔加入欲執行的 class 即可,如圖 3.11 所示為透過「,」分 割的字串陣列,CustomerRunner 會對陣列的每個元素進行 Reflection 並執行,
本研究對於客製程式的執行限制設定的 class 裡的 public method,便於開發者 對客製程式的開發,開發者只需在客製程式裡引入 API 呼叫 Package 的 data getter 與 data setter 即可對 Package 裡的 DATA 欄位進行存取。
圖 3.9 CustomerRunnerDemo.java
圖 3.10 CustomerClass.java package com.demo.customerrunner;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
public class CustomerRunnerDemo {
public static void main(String[] args) throws Throwable {
ClassLoader loader=Thread.currentThread().getContextClassLoader();
Class cla=loader.loadClass("com.test.CustomerClass");
Object clain=cla.newInstance();
Method[] methods=cla.getDeclaredMethods();
for(int i=0;i<methods.length;i++){
if(Modifier.isPublic(methods[i].getModifiers())) System.out.println(methods[i].getName());
System.out.println("---");
methods[i].invoke(clain,new Class[0]);
} } }
package com.demo.customer;
public class CustomerClass { public CustomerClass(){
}
public void get(){
System.out.println("in get method");
}
public static void set(){
System.out.println("in set method");
}
private void hide(){
System.out.println("hide method will not run");
} }
圖 3.11 CustomerRunner-config.xml
MPI Dispatch Module 的子功能如何運作
Task 為管理及啟動 Open MPI 程式重要的執行員角色,包含選用哪些 Node 電腦、如何建立啟動 Command 與檢查需執行的 MPI 程式是否存在等。Task 的 實作為單一線程,取用 MPI Dispatch Module 裡的 Package Checker、Customer Runner、Data Conversion Engine、Node Dispatch 與 Command Maker 對 Package 做處理並建立 Open MPI 的執行 Command,最後利用 MPI Comunication 提交 並接收回傳的 Package,如圖 3.12 所示,每個子功能皆以 getter 與 setter 對 Package 進行存取,此種設計為保持 Package 內容的正確性,且在 getter 與 setter 可統一設計檢查 Package 正確性的邏輯。因不需要立即回應故不使用多執行緒 設計,節省系統資源消耗。
...
<bean id="CustomerBeforeRunnerBean" class="com.demo.spring.bean.
CustomerBeforeRunnerBean ">
<property name="customerbeforeclass">
<value>com.demo.before.classA, com.demo.before.classB</value>
</property>
</bean>
<bean id="CustomerAfterRunnerBean" class="com.demo.spring.bean.
CustomerAfterRunnerBean ">
<property name="customerafterclass">
<value> com.demo.after.classA, com.demo. after.classB </value>
</property>
</bean>
...
圖 3.12 Task 執行 MPI 任務循序圖
Package Checker 為檢查 Package 各欄位值防止假造與不同格式產生的錯誤。
由於啟動 Open MPI 限制使用指令啟動方式,故利用 Data Conversion Engine 將 Package 轉換為 Byte 再轉換為文字加載在指令最後方傳入,MPI 程式在同理反 轉為原始 Package 並取用,如圖 3.13。
圖 3.13 Data Conversion Engine
Node Dispatch 依照存放叢集內電腦狀態的 NodeBean 分派正在閒置或 CPU 使用度低於 70%的偶位數電腦,並建立成字串陣列。Command Maker 將所有 資料建立成 Open MPI 啟動的命令,此部分的命令由外部設定檔建立,並設定 變數,如圖 3.14,其中#{nodes}、#{classpath}、#{program}與#{data}由 Command Maker 注 入 相 應 變 數。 MPI Comunication 核心 為 JAVA 執行 系統 命 令 的 runtime.exec(),設計為單執行緒,只允許單次雙向資訊傳接,接收回傳資訊後 同前述 Data Conversion Engine 反轉回 Package 格式。
圖 3.14 TerminalCommand.properties