使用GPars實現JVM併發和Actors模型

banq發表於2011-04-27
開源專案Gpars是一個在JVM上可以方便且安全平行計算開源框架,GPars提供Actor模型,它比Java傳統基於記憶體多執行緒共享式併發要高效得多,Actors封裝一個個活動物件,他們之間通訊是透過非同步的不可變訊息進行的,不管actor內部擁有什麼狀態,它不能從actor外部訪問,除非發一個訊息給這個actor,然後透過這個訊息獲得其內部狀態。

因為actors處理呼叫訊息是非同步的,他們自己需要啟用活動,一種方式是就分配系統執行緒給一個活動的物件,這樣隨著系統擴充套件,你需要頻繁地分配所有可用的執行緒,所以,一般採取在actors之間共享執行緒,如果一個actor不工作,那麼就回收系統執行緒,不再佔用系統執行緒(banq:類似執行緒池threadPool?)

Actors模型確保處理actor之間處理訊息時不能超過1個執行緒,actor內部狀態就可以被安全地修改(單執行緒),這樣actor是明顯的執行緒安全型。

GPars 提供了actors的Java實現,並且提供適合Groovy和Java方便呼叫的API。Actors實現三個標準操作:發生訊息,接受訊息,建立新Actor。

下面是GPars程式碼:

 final class MyCounterActor extends DynamicDispatchActor 
    {
        private int counter = 0;

        void onMessage(String message) {
            log("Received a string");
            counter += message.length();
        }

        void onMessage(Integer message) {
            log("Received an integer");
            counter += message;
        }

        void onMessage(Boolean message) {
            log("Received a boolean");
            reply(counter);
        }
    }

public class DecryptorTest 
{
    public static void main(String[] args) throws InterruptedException {
        //建立Actor
       	Actor counter = new MyCounterActor().start();
        //傳送訊息
       	counter.send("Hello");
     	System.out.println("Current value is: " + 
		counter.sendAndWait(true));
      	counter.stop();
       	counter.join();
    }
}
<p class="indent">


傳送訊息也有一種方法sendAndWait(),這將會堵塞呼叫者不做任何事,一直等待訊息回覆(類似同步系統)。

Actors分為無狀態Actors和有狀態Actors(banq:一般偏重行為動作的 可用作服務的類都有無狀態和有狀態之分)

無態Actors: DynamicDispatchActor 重複掃描接受的訊息,然後分發給actor中定義的onMessage()方法。
ReactiveActor 是允許更覺類似事件驅動EDA風格,如groovy如下,actor就可以直接將訊息作為引數執行:

final def doubler = reactor {
    2 * it
}

println 'Double of 10 = ' + doubler.sendAndWait(10)
<p class="indent">


Java程式碼有些瑣碎:

Closure handler = new ReactorMessagingRunnable<Integer, Integer>() {
    @[author]Override[/author]
    protected Integer doRun(final Integer value) {
        return value * 2;
    }
};
final Actor doubler = reactor(handler);
<p class="indent">


有態Actors就類似Scala中的actors:

def actor = actor {
    loop {
        log 'Waiting for a gift'
        react {gift ->
            if (myWife.likes gift) reply 'Thank you!'
            else {
                reply 'Try again, please'
                react {anotherGift ->
                    if (myChildren.like gift) reply 'Thank you!'
                }
            }
        }
    }
}
<p class="indent">


Continuations延續:
狀態跨越多個Actor,需要在他們之間延續事務一致性,這稱為Continuations模型,因為JVM不直接支援Continuations,必須在Actor框架中進行模擬。

react 方法是一個執行緒環節中的最後執行方法,一旦到期執行完畢,actor將會把執行緒歸還給系統,同時,react方法是一種下一個訊息到達需要執行的程式碼(閉包),那麼在react將執行緒歸還給系統之間,透過這個閉包將狀態傳遞給下一個訊息,實現類似延續風格的設計。

為了讓actor歸還執行緒,在react方法中寫程式碼:

def myActor = Actors.actor {
    loop {
        react {msg1 ->
            ...
            react {msg2 ->
                ...
            }
            // Never reached
        }
        // Never reached
    }
    // Never reached
}
<p class="indent">

loop迴圈把狀態都遍歷出來用來傳遞給下一個訊息。


總之,GPars是遵循訊息正規化(message-passing paradigms)中的Communicating Sequential Processes (CSP)和 dataflow,能提供Actors如下功能:
Agents代理
Dataflow concurrency資料流併發
Communicating Sequential Processes CSP
Parallel collections並行收集
Fork/Join capabilitiesFork/Join能力
Composable asynchronous functions組合式非同步


JVM Concurrency and Actors with GPars

[該貼被banq於2011-04-27 15:56修改過]

[該貼被banq於2011-04-27 15:56修改過]

相關文章