秒かかるはずの処理を、ここでは二つのアクターに振り分けている。main()さて、処理が終わるのに実際は何秒かかるだろうか?上記のサンプルコードの実行結果は次の通り。sアクターモデルでも設計によっては競合が起こるアクターモデルを使えば、競合が起きないというような説明をされることがたまにあるようだ。その「競合が起きない」というのは、より低レイヤーな側面からアクターモデルを見たときの話だと思う。アクターのメッセージキューを処理するスレッドが一つだけなので、アクターの中で処理が競合しないというのに過ぎない。高レイヤーに、アプリケーションという側面からアクターモデルを見たとき、競合は容易に起こる。それぞれの競合は全く別の次元の話なんだけど、もし混ぜて考えてしまうと危険だ。次は、その競合について見てみよう。サンプルコードでは、銀行口座を模したモデルを用意した。いうユーザを模したアクターが操作する。銀行口座から預金残高を読み取って、その値を元に預金残高を更新する。アトミックになっていないという点だ。銀行口座の読み取りから更新までの間に別のアクターからの処理が割り込む余地がある。サンプルコードでは、口座の読み取りから更新までの間に意図的にスリープを入れることで競合が起こりやすいようにしている。増やすべく処理を実施する。なっていないとおかしい。上記のサンプルコードを実行してみよう。見事に競合が発生している。更新に対してアトミックになっていなかった点だ。いう形でアトミックにしている。現在の預金残高を元に、口座のアクター自体が更新をかけるので、間に別のアクターの処理が入り込む余地はない。アクターの中はメッセージキューを処理する一つのスレッドで処理されているので、同時に同じメソッドが走る心配はない。main()上記のサンプルコードを実行した結果は次の通り。200アクターモデルでも設計によってはデッドロックが起こる典型的なデッドロックは、マルチスレッドでリソースをロックする順番が不定になっていたときに起こる。アクターモデルはロックを使わないので、それならデッドロックが起こらないかというと、そんなことはない。次のサンプルコードではデッドロックを発生させている。メソッドを呼ぶ、というように操作が交差している。すると完了するまでブロックする。双方がお互いの処理の完了を待ってデッドロックを起こしてしまう。main()上記を実行すると、何も表示されずに処理が止まる。対して登録されている。そこで、別のターミナルからこのハンドラに対してシグナルを送ってみよう。9199すると、今のスレッドが何処を処理しているのかトレースバックが表示される。ブロックしていることが分かる。並行処理に関しては、上記のようにしてデバッグができる。スレッドプールっぽいものを作って並行処理をしてみる次はもうちょっと実践的に、スレッドプールっぽく並行処理をしてみよう。いえ、あまり汎用的には作らずベタ書きだけど。