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