環境は Linux Mint 20 です。
Ractor
まずは Ractor。
https://github.com/ruby/ruby/blob/master/doc/ractor.md
https://github.com/ko1/ruby/blob/ractor/ractor.ja.md
下を見ていじくるとよい。
qiita.com
とりあえずこれ。
Ractor.new do 5.times do puts :hello end end 5.times do puts :world end
結果。こうなってしまう。
world world world world world
これは Ractor の生成にコストがかかり、「hello」が出力される前にインタプリタが終了してしまうため。
なので、こうしてみる。
Ractor.new do 5.times do puts :hello sleep(rand(0.1)) end end 5.times do puts :world sleep(rand(0.1)) end
結果。
world hello hello hello world hello world hello world world
うまくいきました。
Thread との比較
Thread。
N = 10 start = Time.now th = N.times.map { Thread.new do a = 0 1_000_000.times {a += 1} Time.now end }.map(&:value) puts th.map {_1 - start}.max #=>0.576966553
Ractor。
N = 10 start = Time.now rs = [] rs = N.times.map { Ractor.new do a = 0 1_000_000.times {a += 1} Time.now end }.map(&:take) puts rs.map {_1 - start}.max #=>0.365015356
4コア環境で、確かに高速化されている。
終わった順にすべての Ractor を待つ
例えばこんなメソッドを作る。
def Ractor.wait_for(*ractors) ractors.size.times.map do r, obj = Ractor.select(*ractors) ractors.delete(r) obj end end
で、こんな感じ。
N = 10 start = Time.now rs = N.times.map do Ractor.new do a = 0 1_000_000.times {a += 1} Time.now end end result = Ractor.wait_for(*rs) puts result.map {_1 - start}
結果。
0.191312097 0.231078089 0.284552986 0.292159854 0.323803118 0.339945751 0.349074802 0.35051055 0.352556214 0.363963214