出自:ibmdeveloperworks ThadomalShahani 23:38 構建自己的基於 Java 的超級電腦 作者:轉載自:如果您曾想過構建自己的超級電腦,但卻對用 C 語言進行並行編程望而生畏,那麼偽遠程線程可以幫您解決這一問題。這種獲獎的 Java 編程模型極大地簡化了叢集上的並行編程,並使超級計算走出實驗室,使每一位 Java 程式員都能使用它。 在過去的三年裡,並行叢集已在改變著超級計算的面貌。一旦價值數百萬美元的單體機佔了主導,並行叢集很快就會成為超級電腦的選擇。可以想像得到,開放源碼圈內的高漲熱情已導致產生了數百 -- 如果不是數千的話 -- 並行叢集項目。第一個同時也是最著名的開放源碼叢集系統是 Beowulf。在 NASA 贊助下,由 Thomas Sterling 和 Donald Becker 在 1994 年發布的 Beowulf,開始是作為一個 16 節點示範叢集推出的。今天,Beowulf 已有數百種實現,從 Oak Ridge 國家實驗室的 Stone SouperComputer 到 Aspen 系統公司的定製構建的商業性叢集(請參閱參考資源)。 對 Java 程式員不利的是,多數叢集系統都是圍繞基於 C 語言的軟體訊息傳遞 API — 如訊息傳遞介面(MPI)或並行虛擬機器(PVM)— 來實現的。用 C 語言進行並行編程不是件容易的事,因此我設計了一個替代方案。本文將說明如何綜合運用 Java 線程和 Java 遠程方法調用(RMI)來建立自己的基於 Java 的超級電腦。 請注意,本文假定您有 Java 線程和 RMI 的應用知識。 超級電腦內有什嗎? 超級電腦的定義是:由八個或更多的節點群組成、作為單個高效能機器工作的叢集。基於 Java 的超級電腦包含一個作業調度器和任意數量的運行伺服器(也稱為主機)。作業調度器產生多個線程,每個線程包含執行不同子任務的代碼。各個線程將其代碼遷移到不同的運行伺服器上。然後,每個運行伺服器執行遷移給它的代碼並將結果返回給作業調度器。最後,作業調度器將各個線程的結果組合起來。 這種並行叢集系統之所以被稱為偽遠程線程,是因為線程是在作業調度器上調度的,但線程內的代碼卻是在遠端電腦上執行的。 該系統有哪些組件? 組件一詞是指組成“偽遠程線程”並行叢集系統的邏輯模組。該系統包含以下組件: Job dispatcher(作業調度器) 是執行控制的機器。它產生不同的線程,每個線程都包含此叢集要處理的主任務的一個子任務。每個線程內的代碼都被發送到一台遠端電腦去執行。線程在作業調度器上調度,所以理論上講,該機器不應該用於執行任何子任務。 SubTask 是一個使用者定義類,該類定義主任務的一個資料或功能獨立的部分。您可以為主任務的不同部分定義不同的類。類名 SubTask 是一個樣本。您可以為一個 SubTask 類取任何名字,不過這個名字應該能描述分配給它的子任務。在定義 SubTask 類時,您必須實現 JobCodeInt 介面以及 jobCode() 方法,下面對其進行說明。 JobCodeInt 是一個 Java 介面。您必須在定義子任務的類中實現該介面和 jobCode() 方法。jobCode() 方法描述了將在遠程執行的代碼。如果您打算在遠程使用某個本地資源,您必須在 jobCode() 方法外部初始化這個資源。比方說,您要將一組映像發送到遠端,就必須在 jobCode() 方法外部初始化 Image 對象。您可以在該方法中調用標準 Java 庫中的類,因為遠端電腦上存在這些庫。 RunServer 是一個 Java 對象,該對象允許遠端程序呼叫其方法。它的一個方法以實現了 JobCodeInt 介面的對象作為參數。 RunServer 就在運行該對象的電腦(運行伺服器)上執行該對象內的代碼,並將計算結果作為 Object 類的一個執行個體返回。Object 是 Java 類階層中最高一級的類。 PseudoRemThr 是一個 Java 類,該類封裝了一個線程並接受給定 SubTask 類的一個執行個體。它選擇一台遠程主機,並將 SubTask 執行個體發送到這台主機上執行。如果您要利用某台主機上可用的特定資源(諸如資料庫或是印表機),則可以指定主機。 HostSelector 是一個模組。如果您沒有指定遠程主機,PseudoRemThr 類就會調用 HostSelector 模組來選擇特定的主機。如果沒有閒置主機,HostSelector 會返回負載最小的遠端電腦。如果某個遠端電腦是一個多處理器系統,HostSelector 可能會不止一次地返回該主機名稱。目前,HostSelector 無法根據給定任務的複雜程度來選擇主機。 偽遠程線程的工作方式 要使用偽遠程線程,您必須實現作業調度器和運行伺服器。本節將說明如何?各個部分。 實現作業調度器 首先,將主任務分解為資料或功能獨立的子任務。針對每個子任務,定義一個實現 JobCodeInt 介面(從而實現 jobCode() 方法)的類。在 jobCode() 方法中,定義各給定子任務要執行的代碼。 請注意,您不能調用作業調度器上使用者定義的的本地資源。請在該方法外部初始化所有這類資源。例如,您可以在 SubTask 類的建構函式中初始化這類資源。 建立類 PseudoRemThr 的若干執行個體,並將 SubTask 的執行個體傳遞給 PseudoRemThr 的各個執行個體。如果您要明確指定一台遠程主機,您可以通過調用 PseudoRemThr 對象的另一個建構函式來完成。 等待這些線程完成。調用 getResult() 方法來擷取 PseudoRemThr 的各個執行個體的執行結果。如果計算沒有完成,結果返回一個值為 false 的 Boolean 對象;否則,將返回 Object 類的一個執行個體,其中包含了計算結果。您必須將此執行個體轉換為您所希望的類類型。將所有的子任務結果組合為最終結果。 實現運行伺服器 實現運行伺服器是一項簡單的工作: 啟動 RMI 註冊程式。 啟動 RunServer。 運行伺服器在啟動時接通作業調度器,並通知作業調度器它已準備就緒,可以接受要執行的任務了。 一個計算樣本 現在該測試這一模型了。以下計算樣本使用兩台電腦並行運行。一台是運行 Windows 98 的 333 MHz Pentium II 電腦,另一台是運行 Windows 2000 專業版的 500 MHz Pentium III 電腦。 為了計算從 1 到 10^9 的所有整數的平方根之和,我建立了 Sqrt 類,它計算 dblStart 和 dblEnd 之間所有整數的平方根之和。 Sqrt 實現 JobCodeInt 介面,因此也實現了 jobCode() 方法。在 jobCode() 方法中,我定義了完成這一計算的代碼。 建構函式用於將資料傳遞給 Sqrt 類,並初始化作業調度器上的所有本地資源。必須將要計算其平方根之和的整數的起止點發送給建構函式。清單 1 是 Sqrt 類的定義 清單 1. 定義 Sqrt 類 //Sqrt 類計算 dblStart 和 dblEnd 之間的所有整數的平方根之和。 //計算在 jobCode() 方法內完成 //該類實現 JobCodeInt 介面,且實現代碼位於 jobCode() 方法內 //在建構函式中將資料傳遞給該類,並初始化作業調度器上的本地資源。 //本例中,要計算其平方根之和的整數序列的起止點被發送給 Sqrt 類 public class Sqrt implements JobCodeInt { double dblStart, dblEnd, dblPartialSum; public Sqrt(double Start,double End) { dblStart = Start; dblEnd = End; } public Object jobCode() { dblPartialSum = 0; for(double i=dblStart;i<=dblEnd;i++) //可調用標準的 Java 函數和對象。 dblPartialSum += Math.sqrt(i); //返回結果,一個標準 Java 類的對象。 return (new Double(dblPartialSum)); } } JobDispatcher 類建立 Sqrt 類的兩個執行個體。然後分解主任務,將一項子任務分配給一個 Sqrt 對象(Sqrt1),並將餘下的子任務分配給另一個 Sqrt 對象(Sqrt2)。接下來,JobDispatcher 建立 PseudoRemThr 類的兩個對象,並將 Sqrt 對象作為參數分別傳遞給它們。接下來就等待線程執行。 一旦線程執行完畢,就可從每個 PseudoRemThr 執行個體獲得部分結果。將各部分結果組合起來即可得到最終結果,如清單 2 所示。 清單 2. 工作中的 JobDispatcher //此類可以命名為您選擇的任何名稱 //這裡選用 JobDispatcher 只是為了方便 public class JobDispatcher { public static void main(String args[]) { double fin = 10000000; //代表 10^9 double finByTen = fin/10; //代表 10^8 long nlStartTime = System.currentTimeMillis(); //範圍從 1 到 3*10^8 Sqrt sqrt1 = new Sqrt(1,finByTen*3); //範圍從 ((3*10^8)+1) 到 10^9 Sqrt sqrt2 = new Sqrt((finByTen*3)+1,fin); //以下建立 PseudoRemThr 類的兩個執行個體。 //此建構函式的參數如下所示。 //第一個參數:代表子任務的某個類的執行個體 //第二個參數:執行這一子任務的遠程主機 //第三個參數:PseudoRemThr 執行個體的描述性名稱。 PseudoRemThr psr1 = new PseudoRemThr(sqrt1,"//192.168.1.1:3333/","Win98"); PseudoRemThr psr2 = new PseudoRemThr(sqrt2,"//192.168.1.2:3333/","Win2K"); psr1.waitForResult(); //等待執行結束//擷取每個線程的結果 Double res1 = (Double)psr1.getResult(); Double res2 = (Double)psr2.getResult(); double finalRes = res1.doublevalue() + res2.doublevalue(); long nlEndTime = System.currentTimeMillis(); System.out.println("Total time taken: " + (nlEndTime-nlStartTime)); System.out.println("Sum: " + finalRes); } } 效能評價 此計算的總執行時間在 120,000 毫秒到 128,000 毫秒之間。如果在不分解任務的情況下在本地運行同樣的任務,執行時間將在 183,241 到 237,641 毫秒之間。 最初,主任務包括計算從 1 到 10^7 的所有整數的平方根之和。為測試效能,我將計算範圍擴大到 10^8,最終擴大到 10^9。 隨著任務量的增加,遠程並存執行和本地執行所需時間的差別也越來越明顯。這就是說,當執行大型任務時,遠程並存執行消耗的時間較少。遠程並存執行並不適合小型任務,因為機器間通訊的系統開銷不容忽視。隨著任務量的增加,機器間通訊的開銷與在單個機器上執行全部任務的開銷相比逐漸層得微不足道。因此,我得出以下結論:偽遠程線程系統能很好地完成需要進行大量計算的任務。 使用偽遠程線程有哪些優點? 因為偽遠程線程是一種基於 Java 的系統,它可以用於實現包含多種作業系統的叢集,或異構叢集。使用偽遠程線程,您就避免了轉換原有 C/C++ 代碼的麻煩,而且還能利用 Java 標準庫及其各種擴充庫。此外,偽遠程線程使您不必關心記憶體管理。當然,其缺點就是系統效能與 JRE 效能直接相關。 發展方向 現在相當多的商務應用程式都是用 Java 平台建立的,並考慮到為了利用並行性需要轉換原有的 C/C++ 代碼的實際困難,現在可能是基於 Java 的超級計算進入商業領域的時候了。在開始建立基於 Java 的應用程式時就將並行性和負載平衡考慮在內是個不錯的開端。 互連網就是異構叢集的一個很好的例子,因此偽遠程線程可以在網際網路中部署,將 Web 轉換為一個單一的、基於 Java 的超級電腦(要瞭解這一概念的細節,請參閱參考資源)。然而,從實際應用出發,您應注意到在一個專門執行單一任務的同構叢集中將獲得最佳結果。 最後,從日常應用出發,偽遠程線程使得將區域網路(LAN)-- 諸如校園網和家庭網 -- 轉換為微型的超級電腦變得相當簡單。這就是 Beowulf 系統開創的用法。有了偽遠程線程,Java 編程人員也可以建立自己的超級電腦了。 參考資源 "Linux clustering cornucopia"(developerWorks, 2000 年 5 月)為您指點迷津,讓您瞭解當前 Linux 上可用的開放源碼叢集解決方案和保密源碼叢集解決方案。 要瞭解關於分布式作業系統的詳細資料,請查看 Andrew S. Tanenbaum 的 Modern Operating Systems(Prentice Hall 出版公司,1992 年 2 月)。 要瞭解關於並行編程的詳細資料,請參閱 Gregory V. Wilson 的 Practical Parallel Programming(麻省理工學院出版社,1995 年 12 月)。 要進一步理解叢集,請參閱 Scalable Computing Laboratory 的 Cluster Cookbook。 有關運用 Java 技術和 Web 進行超級計算的深層探討,請參閱 Laurence Vanhelsuw 的 "Create your own supercomputer with Java?" (JavaWorld, 1997 年 1 月)。 Linux document.tion Project 託管著 Beowulf HOWTO 文檔。 訪問 Beowulf 網站,以瞭解 Beowulf 項目的詳細資料。 請參閱關於 Oak Ridge 國家實驗室著名的 Stone SouperComputer 的詳細資料。 Aspen 系統公司是目前提供定製叢集解決方案的少數廠商之一。
|