使用future實現內建非同步API

banq發表於2010-01-19
當設計併發策略時,要將 "what做什麼"和 "how怎麼做"進行分離,

Prefer Futures to Baked-In "Async APIs"一文介紹瞭如何使用語言的並行API透過非同步來實現這點。

普通同步性質的方法如下:

RetType DoSomething(
  InParameters ins,
  OutParameters outs
);
<p class="indent">


如果DoSomething 將花費很長時間執行,無論它是否耗費CPU,比如從資料庫中載入一個資料就是很耗費時間的,那麼是不是在DoSomething執行的同時,我們做做其他事情呢?

比如:

result = DoSomething( this, that, outTheOther );
OtherWork();
<p class="indent">


如果OtherWork不依賴result 這個值,那麼我們讓DoSomething使用通常意義上的非同步執行就沒有問題。

但是如果OtherWork依賴上一步執行結果result,怎麼辦?

第一個方案是使用Begin/End 模式實現:
設計一個開始介面,如下

IAsyncResult BeginDoSomething(
  InParameters ins
);
<p class="indent">

再設計一個結果介面,如下:

RetType  EndDoSomething(
  IAsyncResult asyncResult,//上一介面計算的結果
  OutParameters outs
);
<p class="indent">


使用方式如下程式碼:

IAsyncResult ar = BeginDoSomething( this, that );
result = DoSomething( this, that, outTheOther );

//在DoSomething執行同時,執行OtherWork
OtherWork();

//將上面兩個融合Join, 
ar.AsyncWaitHandle.WaitOne();//必要時需要等待
result = EndDoSomething( ar, outtheOther );

<p class="indent">


這個模式需要在最後等待,無論DoSomething和OtherWork哪個先做完,都要等待對方,這個效能會很差,當然該文從.NET框架等多個角度說明這個模式一些侷限,這裡不再引述,可以參考原文。

我們主要目的是要將“如何非同步執行這個工作 ”(也就是呼叫"how如何做")和做什麼分離開來。在上面這個案例中,我們關注的是讓DoSomething和OtherWork非同步啟動,而DoSomething如何非同步執行(how),應該不是我們關心的,至少應該從上面這段呼叫程式碼中分離出去。而 begin/end 模式並沒有幫助我們做到這點,相反是將How和What耦合在一起了。

讓我們來看看如何實現How和What分離解耦:
1.使用一個分離的Task任務呼叫來執行How的工作內容,根據你的語言平臺,比如如果是Java/.NET,使用pool.run( /*task*/ ),如果C++0x,使用async( /*task*/ ) .

2.使用futures來管理非同步執行的結果. 這實際就是類Java JDK中的Future<T> API, C++0x標準即將也會有,而.NET下一個版本使用的是Task<T>.

這樣,上面案例程式碼如下:

//第一步 asynchronous call
future<int> result =
  async( ()=<{ return CallSomeFunc(x,y,z); } );


//第二步  code here runs concurrently with CallSomeFunc 
//同時執行其他事情

//第三步 use result when it's ready (this might block)
//在這裡使用非同步執行dosomething的結果
DoSomethingWith( result.value() );
<p class="indent">


這裡程式碼為什麼和前面程式碼不完全一致,因為我們根據How和What分離,更改了設計,如果前面案例的otherwork依賴DoSomething的結果,那麼,我們就要將otherwork內容進行分解,將otherwork中不依賴DoSomething結果的內容首先執行,也就是上面第二步,然後,使用在第三步,我們將兩個計算結果融合。

這種使用Future特性將How和What分離的模式,已經被使用在JdonFramework 6.2的Domain Events,實際就是Domain Events的內在機制,當領域模型中啟用一個事件時,實際就是傳送了一個訊息,在JdonFramework中,監聽訊息實際執行如下程式碼:

private void asynExecMessageListener(final DomainMessage message) {
 FutureTask futureTask = new FutureTask(new Callable<Boolean>() {
    public Boolean call() throws Exception {
	try {
        	message.getMessageListener().action(message);
	} catch (Exception e) {
                 ....
		return true;
	}
	});

	message.addFutureTask(futureTask);//執行futuretask
	executor.execute(futureTask);//相當於pool.run

	}
<p class="indent">


應該說:JdonFramework 6.2是將EDA和Java平行計算,非同步可伸縮性融合在一起,在設計理念是先進的,本文也可以驗證這點。參考Domain Events非同步應用

[該貼被admin於2010-01-20 09:22修改過]

相關文章