2007年12月17日 星期一

GridGain 程式開發(7) - Gridify With State

接著這個範例,將 grid-enabled method 從原本的程式中抽離出來,自成一個 class。

而這個 class 除了 grid-enabled method 以外,還包含了狀態(state)資訊,以及處理各狀態資訊所需要的 method。


AspectJ AOP 設定

然而,要使用這個功能,AOP 相關的設定也不能忘掉!

此處使用 AspectJ AOP,因此在 eclipse 上就必須要設定相關的啟動參數,因此在「Run Dialog」中設定:
  1. 在 Arguments -> VM arguments 中,設定以下內容:(GRIDGAIN_HOME 要自行取代掉!)
    -javaagent:[GRIDGAIN_HOME]/libs/aspectjweaver-1.5.3.jar

  2. 在 Classpath 中,透過 Advanced 按鈕加入以下 External Folder:
    [GRIDGAIN_HOME]/config/aop/aspectj


範例程式

為了簡單說明,state 資訊僅使用字串來表示,當然也可以是複雜的資料結構,端看使用者所需要的功能為何,以下就用範例程式來說明:

GridifyHelloWorld.java
import org.gridgain.grid.gridify.Gridify;

public class GridifyHelloWorld {
//設定 state 為 String
private String state = null;

// ========== 處理 state 相關 methods ========== (begin)
public String getState() {
return state;
} //end getState

public void setState(String state) {
this.state = state;
} //end setState
// ========== 處理 state 相關 methods ========== (end)

/**
* 透過「@Gridify」annotation 將此 method 變為 grid-enabled
* 並透過 taskClass 關鍵字指定 class 作為將 state 資訊拆開並傳送到 grid node 處理的 GridTask
*/

@Gridify(taskClass=GridifyHelloWorldStateTask.class, timeout=3000)
public void sayIt() {
System.out.println("\n=========== remote 開始執行 ===========");
System.out.println(">>>> 印出 " + this.state);
System.out.println("=========== remote 執行完畢 ===========\n");
} //end sayIt
}
GridifyHelloWorldStateTask.java
import java.io.*;
import java.util.*;
import org.gridgain.grid.*;
import org.gridgain.grid.gridify.*;

/**
* 繼承 GridTaskSplitAdapter,必須實作 split 與 reduce 兩個 method
*
* 【
GridifyArgument
* 為 grid-enabled method 所屬的 class(此範例為 GridifyHelloWorld) 的 instance 的反射(reflection)
* 透過 reflection< 的機制,可以取回 class instance 相關資訊
* */

public class GridifyHelloWorldStateTask extends GridTaskSplitAdapter<GridifyArgument> {

/**
* 將 task 拆成多個 jobs 並丟到 grid node 去執行
*/

@Override
protected Collection<? extends GridJob> split(int gridSize, GridifyArgument arg) throws GridException {
//取得 grid-enabled method 所屬的 class(GridifyHelloWorld) instance
GridifyHelloWorld hello = (GridifyHelloWorld)arg.getTarget();

String[] words = hello.getState().split(" ");

//產生存放 GridJob 的 List 容器
List<GridJobAdapter<String>> jobs = new ArrayList<GridJobAdapter<String>>(words.length);

//指定 job 所要處理的工作,並加入 List 容器中
for(String word : words) {
jobs.add(new GridJobAdapter<String>(word) {

/**
* 執行 grid-enabled method<br />
* 使用的參數為上面傳入的參數 word (透過 getArgument() 取得)
*/

@Override
public Serializable execute() throws GridException {
GridifyHelloWorld hello = new GridifyHelloWorld();
hello.setState(this.getArgument());
hello.sayIt();

return null;
} //end execute

});
} //end loop

return jobs;
} //end split

/**
* reduce 的目的是將多個 job 所回傳的值匯集起來,並轉為單一物件輸出<br />
* 而這個物件會由 GridTaskFuture.get() 所取得<br />
* 此範例中不需回傳值,因此直接回傳 null
*/

@Override
public Object reduce(List<GridJobResult> arg0) throws GridException {
return null;
}
}
GridifyHelloWorldStateExample.java
import org.gridgain.grid.*;
import org.gridgain.grid.gridify.*;

public class GridifyHelloWorldStateExample {
public static void main(String[] args) throws GridException {
GridFactory.start();

try {
GridifyHelloWorld hello = new GridifyHelloWorld();

hello.setState("Hello this World!");

hello.sayIt();

//此行僅會在本地端執行
System.out.println("\n=========== local 執行完畢 ===========\n");
} finally {
GridFactory.stop(true);
}
}
}
由於這幾個範例程式也是使用了 AOP 機制,因此在 sayIt() method 的呼叫也是容易產生混淆! 以下稍微說明一下程式執行流程:
  1. 產生 GridifyHelloWorld instance,並設定此 instance 的 state 資訊

  2. 呼叫 grid-enabled sayIt() method,但不會印出任何 state 資訊,而是由 aspectJ 呼叫 GridGain,並根據 GridifyHelloWorldStateTask 中的 split 實作來將 task 拆成多個 jobs(以空白為間隔拆開 state 資訊)

  3. 接著 GridGain 會將包含 grid-enabled method 的 class 序列化(serialize)後,傳到 remote grid node 準備執行

  4. remote gird node 將其反序列化(deserialize)之後,根據此 class 產生新的 instance,並根據接收到的字串重新設定 state 資訊

  5. 當 state 資訊設定完成,最後再呼叫 sayIt() method,此時 GridGain 不會再度將其視為 task 而只是將 state 資訊輸出

最後,透過這種方式,使用者就可以將 business logic 以另外開發成 module 的方式去寫了! 不需要通通嵌在原本包含控制 grid 的相關程式之中,開發起來也較為簡潔易懂!!


更簡單的開發方式

同樣的,以下將上面程式修改為較容易理解的版本,修改後的執行結果也是相同的!

GridifyHelloWorld.java
import org.gridgain.grid.gridify.Gridify;

public class GridifyHelloWorld {
private String state = null;

public void setState(String state) {
this.state = state;
} //end setState

public String getState() {
return this.state;
}

// ***************** 修改的部分 ***************** (Begin)
@Gridify(taskClass=GridifyHelloWorldStateTask.class, timeout=3000)
public void splitGridTask() {
//這裡只要加入足夠的 annotation 資訊即可
//不需要任何實作,只是告知 GridGain 作 split task 的動作
} //end splitGridTask

public void sayIt() {
System.out.println("\n=========== remote 開始執行 ===========");
System.out.println(">>>> 印出 " + this.state);
System.out.println("=========== remote 執行完畢 ===========\n");
} //end sayIt
// ***************** 修改的部分 ***************** (End)
}
GridifyHelloWorldStateTask.java
僅為 GridTask 拆開成為 GridJob 的部分,因此不需更改!
GridifyHelloWorldStateExample.java
import org.gridgain.grid.*;

public class GridifyHelloWorldStateExample {

public static void main(String[] args) throws GridException {
GridFactory.start();

try {
GridifyHelloWorld hello = new GridifyHelloWorld();

hello.setState("Hello this world!");

// ***************** 修改的部分 ***************** (Begin)
//將 GridTask 拆成多個 GridJob,並執行工作
hello.splitGridTask();
// ***************** 修改的部分 ***************** (End)

System.out.println("\n=========== local 執行完畢 ===========\n");
} finally {
GridFactory.stop(true);
}
}
}

修改成以上這個版本之後,應該是會比較容易瞭解了!

沒有留言:

張貼留言