GoF以外のプログラミング・デザインパターン #10 Actor Model

2025/12/01

プログラミング 学習

t f B! P L
eyecatch Actor Model(アクターモデル)は、「オブジェクト指向を超えた並行処理モデル」です。 すべての処理単位を「Actor(アクター)」として扱います。 どう言うことかと言うと、 「Actor」は、独立したスレッド的存在として、 メッセージを受け取り、自分の内部状態を変え、必要なら他のActorへメッセージを送る役割を担います。 共有メモリを使わず、メッセージパッシングで通信することで、 並列・分散処理に強い(デッドロックや競合が起きにくい)設計になります。

基本構造

Actorは以下の3つの動作しか持ちません。
1. メッセージを受け取る 2. 内部状態を更新する 3. 他のActorへメッセージを送信する

イメージ図

[ Actor A ] ──▶ [ Actor B ] ▲ │ └───────◀──────┘ 各Actorは独立して動作します。 メッセージは非同期に送受信します。 グローバル変数や共有リソースは持ちません。

Reactor / Proactor との違い

比較項目 Reactor / Proactor Actor Model
主眼 I/Oイベント処理 並行タスク管理
データ共有 共通スレッド/コールバック メッセージ通信のみ
構造 中央制御+ハンドラ 分散制御(各Actorが自律)
実装例 Node.jsのEventLoop Erlang, Akka, Orleans

JavaScript的理解

JS自体はシングルスレッドだが、 Web WorkerやMessageChannelを使うと「Actor的」構成を再現できる。 各Workerが「Actor」であり、postMessage() が「メッセージ送信」。 なので、並列に動作しつつ、共有メモリを持たない。

簡易サンプル(Actor風実装 in JavaScript)

// Actorを定義 class Actor { constructor(name, behavior) { this.name = name; this.behavior = behavior; } // メッセージを受け取る receive(message) { console.log(`[${this.name}] 受信:`, message); this.behavior(this, message); } } // Actor間通信システム class ActorSystem { constructor() { this.actors = {}; } register(actor) { this.actors[actor.name] = actor; } send(to, message) { const actor = this.actors[to]; if (actor) actor.receive(message); } } // Actorシステム構築 const system = new ActorSystem(); // Actor定義 const greeter = new Actor("Greeter", (self, msg) => { console.log(`[Greeter] ${msg.from} に挨拶を送信`); system.send(msg.from, `こんにちは、${msg.from}さん!`); }); const user = new Actor("User", (self, msg) => { console.log(`[User] 受信: ${msg}`); }); // 登録 system.register(greeter); system.register(user); // メッセージ送信 system.send("Greeter", { from: "User" });

このサンプルのポイント

・ActorSystem が「メッセージルーター」 ・Actor は「自律的なオブジェクト」 ・send は非同期通信を模した呼び出し ・Greeter と User はお互いに状態を共有しない

メリット

・並列・分散処理が自然に書ける ・デッドロックやレースコンディションを防ぎやすい ・スケーラブル(Actorを別プロセスや別ノードに移動できる)

デメリット

・状態共有ができないため、設計がメッセージ中心になりがち ・通信コストが増える(大量のメッセージ交換) ・デバッグが難しい(非同期メッセージの追跡が困難)

有名な採用例

・Erlang / Elixir(BEAM VM)  → 電話交換機や分散システムに使用 ・Akka(Scala/Java)  → JVM上のActorフレームワーク ・Microsoft Orleans(.NET)  → Azureやクラウド向けActorモデル

あとがき

サンプルコードを見て、JavascriptのPostMessageと同じなのではないか?と思った人もいるかと思います。 厳密に言うと、ActorモデルとPostMessageは、かなり違い概念ですが、実際は少し違います。 大きな違いは、Actorモデルは双方でデータを共有しますが、PostMessageは、データを送信するだけで共有されません。 なので、PostMessageは、処理完了を待たないので、Callback処理ができません。 これらの視点に気がついた人は、設計に安定感が生まれると思います。 重要なのは、デザインパターンは、適材適所でしっかりと設計することができるという点でしょうね。

人気の投稿

このブログを検索

ごあいさつ

このWebサイトは、独自思考で我が道を行くユゲタの少し尖った思考のTechブログです。 毎日興味がどんどん切り替わるので、テーマはマルチになっています。 もしかしたらアイデアに困っている人の助けになるかもしれません。

ブログ アーカイブ