@ledsun blog

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

切符を通したときだけ通れる改札口Ractor

前回、Ractor.selectでtakeとrecvを両方待てることがわかりました。 これを使って切符を通したときだけ通れる改札口を作ります。

完成形

キーボード入力を待つRactor = Ractor.new { loop { Ractor.yield gets.chomp } }

改札口Ractor = Ractor.new(キーボード入力を待つRactor) do |キーボード入力|
  ゲート = :閉

  loop do
    # キーボード入力と自身へのメッセージを両方待つ
    メッセージの種類, 受信したメッセージ = Ractor.select キーボード入力, self

    if メッセージの種類 == :recv
      ゲート = :開
    else
      Ractor.yield 受信したメッセージ if ゲート == :開
      ゲート = :閉
    end
  end
end


loop do
  改札口Ractor.send 'に切符を入れる'
  入場者 = 改札口Ractor.take

  p "#{入場者} が入場しました"
  sleep 1
end

実行すると、たくさんキー入力をしても、1秒に一回だけ受け付けます。

感想

Ractor.selectの戻り値の第一引数、自身へのイベントだと:recv帰ってくるのですね。selfが帰ってくるのかと思っていました。

なんだろう、この・・・ES5以前のJavaScript感。懐かしい。クラスを作らないで...

  1. Ractorでスコープを切る
  2. ブロック内のローカル変数で状態を持つ
  3. Ractor.newで定義と同時に、外部への参照を受け取る(実行する)

モジュールパターンやんけ!

var module1 = function(initState){
  var state = initState

  return {
    getState: function(){
      return state
    },
    setState: function(newVal){
      state = newVal
    }  
  }
}('hoge')

みたいな、関数スコープしかなかった時代にプライベートな状態を持つオブジェクトを作るためにやっていた工夫と似ている点を感じました。