Actor 模型最初是為大量獨立微型處理器構建的高性能網絡而設計,如今隨著多核處理器的普及,它再次成為並行編程的焦點。其核心理念極簡:「萬物皆 Actor,Actor 間透過消息通信」。執行特徵有二:每個 Actor 單線程順序處理消息;不同 Actor 可並發執行。雖然關於 Actor 是否可並行處理消息、是否保證消息到達順序仍有爭議,但其天生的並發特性毋庸置疑。
現實中,線程作為系統最小執行單元,數量有限且開銷大。Actor 模型在概念上允許成千上萬個 Actor「同時運行」(即處於運行狀態),極大地提升了並發想像空間。
Erlang 以 Actor 模型為設計準則,其 Actor 稱為「進程」,僅做三件事:創建進程、發送消息、接收處理消息。代碼示例展示了一個簡單的命名服務,利用模式匹配和尾遞歸實現循環:
loop() ->
receive
{From, {store, Key, Value}} ->
put(Key, {ok, Value}),
From ! {kvs, true},
loop();
{From, {lookup, Key}} ->
From ! {kvs, get(Key)},
loop()
end.
Erlang 的類型系統雖顯簡陋,但模式匹配與尾遞歸讓 Actor 邏輯表達極為優雅。
Scala 內置 Actor 庫充分利用語法特性,使 Actor 如同原生功能。以下 Pong Actor 示例使用 while(true) 循環與 case 匹配消息:
class Pong extends Actor {
def act() {
var pongCount = 0
while (true) {
receive {
case Ping =>
if (pongCount % 1000 == 0) Console.println("Pong: ping " + pongCount)
sender ! Pong
pongCount = pongCount + 1
case Stop =>
Console.println("Pong: stop")
exit()
}
}
}
}
Actor 調度分兩類:
react 替代 receive 實現此模式。主流實現(Erlang、Scala)多採用事件調度並由系統統一管理資源;而 MS CCR、Retlang、Jetlang 等需顯式指定線程池,雖效率可能更高但複雜度增加。本文將實現的 ActorLite 同樣採用事件調度,直接利用 .NET 線程池簡化資源分配。
