読者です 読者をやめる 読者になる 読者になる
無料で使えるシステムトレードフレームワーク「Jiji」 をリリースしました!

・OANDA Trade APIを利用した、オープンソースのシステムトレードフレームワークです。
・自分だけの取引アルゴリズムで、誰でも、いますぐ、かんたんに、自動取引を開始できます。

Thread#valueでFutureパターン

Ruby

Futureパターンは、時間のかかる処理の非同期実行と処理完了の待ち合わせをスマートに行うためのパターンです。

  • 非同期スレッドの開始や待ち合わせ処理を、非同期実行を開始する関数と引換券に隠蔽し、
  • 呼び出し側や時間のかかる処理でスレッドを意識する必要なしに、処理を非同期実行できるようにします。

RubyではThread#valueを使うとさくっと作れます。

# 処理の実行結果を得るための引換券
class Future
  def initialize( t )
   @t = t
  end

  # 処理の実行結果を得る。
  # - 処理が実行完了していなければ実行完了を待ち、結果を返す。
  # - 実行完了していれば、即座に結果を返す。
  # - 処理の途中で例外となっていれば、例外をスロー
  def get_result
   @t.value
  end
end

# 指定したブロックを非同期実行し、
# 結果を取得するための引換券を返す。
def do_asynch ( &block )
  t = Thread.new &block
  return Future.new(t)
end

利用サンプルです。

  • do_asynchで非同期実行を開始し、Future#get_resultで結果を取得します。
  • Future#get_result呼び出し時に処理が終了していなければ完了するまで待たされます。
  • 非同期実行する処理や呼び出し側のサンプルでスレッドを意識していないのがポイント。
result = do_asynch {
  10.times { |i| # 5秒待って結果を返す。
    puts ".. " << i.to_s
    sleep 0.5
  }
  "end"
}
puts "wait start."

# 引換券から値を取得。
# 処理の完了までブロックされる。
puts result.get_result


# 処理終了後は即座に結果が返る
result = do_asynch {
  "end"
}
sleep 1
puts result.get_result

# 処理の途中で例外が発生した場合、それをスロー
result = do_asynch {
  raise "test"
}
puts result.get_result

実行結果です。

.. 0
wait start.
.. 1
.. 2
.. 3
.. 4
.. 5
.. 6
.. 7
.. 8
.. 9
end
end
xxx/future.rb:49: test (RuntimeError)
	from xxx/future.rb:14:in `value'
	from xxx/future.rb:14:in `get_result'
	from xxx/future.rb:51

というか。

Futureでラップする必要はなかったり。呼び出し側でスレッドが出てくるけど、むしろ変に隠蔽されない方がわかりやすい!、という人はこれで。

result = Thread.fork {
  10.times { |i| # 5秒待って結果を返す。
    puts ".. " << i.to_s
    sleep 0.5
  }
  "end"
}
puts "wait start."
puts result.value

実行結果です。

.. 0
wait start.
.. 1
.. 2
.. 3
.. 4
.. 5
.. 6
.. 7
.. 8
.. 9
end