- Ruby 4.0 の Ractor 使ってみた (1) 触ってみるまで
- Ruby 4.0 の Ractor 使ってみた (2) 題材
- Ruby 4.0 の Ractor 使ってみた (3) Ractor::Port に馴染む
- Ruby 4.0 の Ractor 使ってみた (4) Ractor に馴染む
- Ruby 4.0 の Ractor 使ってみた (5) 設計方針
- Ruby 4.0 の Ractor 使ってみた (6) 実装
- Ruby 4.0 の Ractor 使ってみた (7) ベンチマークテスト
ここでいきなり実装にかかるのではなく,ひとまず Ractor およびポートという概念に親しんでおこう。
まずはポートから。
なお,この記事は Ruby 4.0.2 で動作確認している。
実験しながら書いているので誤解があるかもしれない。間違ってたら教えてほしい。
ポートとは
Ruby 4.0 で行われた Ractor の最大の改変は,ポートという概念の導入であった。
ポートは Ractor::Port というクラスのインスタンスだ。
私の理解が正しければ,ポートは Ractor が外界とやり取りするための窓口で,そこからオブジェクトをもらったり,そこへオブジェクトを渡したりするもの。
すべてのポートは,それを作った Ractor に属す。
ポートの基本動作
ポートは Ractor::Port.new で作れる。
ポートにオブジェクトを渡すには send メソッドを使い,ポートからオブジェクトをもらうには receive メソッドを使う。
port = Ractor::Port.new
port.send "foo"
port.send "bar"
p port.receive # => "foo"
port.send "baz"
p port.receive # => "bar"
p port.receive # => "baz"
port.receive # ここで待ちが生じる → スクリプトは終了しない
これを見て以下のようなことが分かる。
- ポートに
sendした順にreceiveされる - 受け取れるオブジェクトが残っていないときに
receiveしようとすると,待ちが生じる(誰かが新たにsendするまで待っている)
この動作だけ見ると「なんだかキュー(queue)みたいだな」と感じる。
実際,キュー的な面もあるのだろうけど,ポートが役立つのは,これを介して異なる Ractor 同士がオブジェクトをやり取りするときなのだろう。
なお,Ractor::Port#send には << というエイリアスがあるので,
port.send "foo"
は
port << "foo"
と書いてもよい。
ところで,上記のコードのどこにも Ractor は出てきていない。
すべてのポートは何らかの Ractor に属すはずだが,上記の port はどうなっているのか?
実は「メイン Ractor」と呼ばれる暗黙の Ractor が存在している。
Ractor を全く意識しないで書いたコードも,実はメイン Ractor で動いているのだ。
上記の port はメイン Ractor 内で生成したから,当然メイン Ractor に属している。
次は Ractor を触ってみよう。