Worker

同じ重い合計を二度走らせる画面です。片方はページの中、もう片方は別のスレッドです。横で数字が 60ms ごとに動いているので、どちらのときに画面が止まるかが見えます。

止まるのはメールボックスのせいではない

JavaScript は一本しか走りません。同期で回る計算は、誰が書いても画面を止めます。 アクタの仕組みとは関係ありません。測るとこうなります。

300ms の計算をどこで回すか他のアクタが感じた最大の間隔
同じスレッド338 ms
Worker34 ms(何もしていないときと同じ)

置き場所を書くのは一行だけ

仕事をするアクタは、普通の ActorRef で掴みます。

a := Worker spawn: (Adder named: '集計' to: sink) on: w.

(a ask sumTo: 100000) forced printNl.

どこで走るかを言っているのは Worker spawn:on: の一行だけです。asktell も、相手が同じスレッドにいるときと同じに書きます。参照には、そのアクタがどこで動くかが書かれていません。

渡せないものはコンパイル時に止まる

スレッドを跨ぐとき、状態もメッセージもコピーされて渡ります。だからブロックは渡せません。作られた場所を閉じ込めているからです。

これはコンパイル時に止まります。ブロックを持った状態を Worker に置こうとすると、どの項目が原因かまで言われます。

the state placed on a worker cannot cross an actor boundary: it is Job,
whose work is Block[Int -> Int], and a block closes over the scope it was
made in

Decimal も Date も Dict も、意味を保ったまま渡ります。structuredClone にそのまま任せると、Decimal は中身がむき出しの入れ物になって届きます。金額が境界を越えて金額でなくなるので、線上の表現は自前で持っています。

落ちたときも同じ

Worker の上のアクタを落とすと、監視している側に down: が届きます。スレッドを跨いでも同じです。