使用future實現內置異步API

當設計併發策略時,要將 "what做什麼"和 "how怎麼做"進行分離,
Prefer Futures to Baked-In "Async APIs" 一文介紹瞭如何使用語言的並行API通過異步 來實現這點。

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

RetType DoSomething(
  InParameters ins,
  OutParameters outs
);


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

比如:
result = DoSomething( this
, that, outTheOther );
OtherWork();


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

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

第一個方案是使用Begin/End 模式實現:
設計一個開始接口,如下
IAsyncResult BeginDoSomething(
  InParameters ins
);

再設計一個結果接口,如下:
RetType  EndDoSomething(
  IAsyncResult asyncResult,//上一接口計算的結果


  OutParameters outs
);



使用方式如下代碼:
IAsyncResult ar = BeginDoSomething( this
, that );
result = DoSomething( this
, that, outTheOther );

//在DoSomething運行同時,執行OtherWork


OtherWork();


//將上面兩個融合Join, 


ar.AsyncWaitHandle.WaitOne();
//必要時需要等待


result = EndDoSomething( ar, outtheOther );




這個模式需要在最後等待,無論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() );



這裏代碼爲什麼和前面代碼不完全一致,因爲我們根據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



	}



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

 

原文:http://www.jdon.com/jivejdon/thread/38006

發佈了215 篇原創文章 · 獲贊 0 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章