• 作成:

Actix 0.8でActorを別のスレッドで実行する

Actor model by Rust with Actix - Qiitaはとても参考になる良記事で公式ドキュメントより優れている面すらあります.公式ドキュメントActix Quickstart - Actixは「WIP」で章が終わっている場所すらあるので…

ただ0.7準拠というのが残念なポイントですね.現在(2019-05-30T19:14:10+09:00)のActixのバージョンは0.8.2なので.

特にArbiterに関するAPIは大幅に変わっていて,startメソッドなんて消滅しています.

さて今回私が詰まったのはネットワークに関するブロッキングです.1つのActorの中でread_untilメソッドを使っていて,これが全てのActorをストップさせてしまっているのです.

ブロッキングする処理はSyncArbiterに回せますが,そのActorは普通にContextでnotifyを使っているためSyncContextに変換することは困難です.もちろん注意深くread_untilにタイムアウトを設定するなどでブロッキングを回避することは可能でしょうが,どの操作がブロッキングするのかわからないのに全部潰すのは気合と根性が必要で私はそれを持っていません.

新しいスレッドを立ち上げてそちらに任せてしまうことにしましょう.

それで0.8でのスレッド(Arbiter)でのActorの実行方法がよくわからなくて探しました.

解決方法はActor::start_in_arbiterを使うことです.ActorはTraitなので一応Actorを実装した何かしらの型のメソッドを参照することになるでしょう.どうせ大抵はデフォルト実装されてますが…

    let foo_actor = FooActor::new();
    FooActor::start_in_arbiter(&Arbiter::new(), |_| foo_actor);

のようにして使います.

ここで注意が必要なのはstart_in_arbiterのクロージャ内部でアクターを初期化しようとしないことです.これでスレッドセーフじゃないと言われて十数分悩みました.

これで別スレッドなのでブロッキングに悩む必要はなくなりました.

でも正直他の言語みたいに全部別スレッドになってしまって,内部で軽量スレッドのワーカーがぶん回す方がお手軽感はありますね.Rustにもそういうフレームワークはありそうですが.手軽さの問題ならそれやるだけの関数追加すれば良いのか…?

ところでこのArbiterさん参照で渡されて所有権失われてないけどどういう原理でスレッド除去されるんでしょう…ドキュメントを見ると除去されるっぽいですし,流石にされないとおかしいと思うのですが.まだ要調査ではありますね.