@ledsun blog

無味の味は佳境に入らざればすなわち知れず

Ractor間のメッセージ送受信 Pull型とPush型

やることは前回と同じです。Ractorの構成を組み替えてみました。

Pull型とPush型

Ractorのメッセージ送受信にはPull型とPush型があります。 前回、メインスレッド(?)でRactorインスタンスをselectしてイベントを待ちました。Pull型です。

f:id:ledsun:20200422213039p:plain
Pull型

今回、描画用のRactorインスタンスrendererを用意して、他のRactorインスタンスからイベントをsendします。Push型です。

f:id:ledsun:20200422213126p:plain
Push型

完成形

require 'io/console'

# 結果を描画するRactor。inputとclockの存在を知りません。
renderer = Ractor.new do
  val = 0
  loop do
    # メッセージを待ちます
    msg = Ractor.recv

    # メッセージがユーザー入力だったら値をリセットします。
    val = 0 if msg == :reset

    # カウントアップします。
    val += 1
    # 行をクリア
    print "\e[2K"
    # 行頭へ移動
    print "\e[0G"
    # 出力
    print val
  end
end

# ユーザー入力を待つRactor。引数でrendererを受け取ります。
input = Ractor.new renderer do |renderer|
  # moveされたSTDIOを使って文字入力を待つ
  io = Ractor.recv
  while "\C-c" != io.getch
    # メッセージを送ります
    renderer << :reset
  end
end

# クロックイベントを発生するRactor。引数でrendererを受け取ります。
Ractor.new renderer do |renderer|
  loop do
    # メッセージを送ります
    renderer << nil
    sleep 0.3
  end
end

# 共有不可能オブジェクトSTDINをRactorにmoveする
input.send STDIN, move: true

# Ractorの終了を待つ?
Ractor.recv

はまったところ

Ractor.recvを書かずに実行したら、何も出力されずにプログラムが終了しました。 Ractorインスタンスが動き出す前に、メインスレッド(?)が終了したようです。

感想

Pull型とPush型では、Ractor間の依存関係が逆転しました。 この規模では、ふーんて感じです。