ruby 3.0.0preview1 をちょっと使ってみる

環境は 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