def fibo(n) n <= 2 ? 1 : fibo(n-1) + fibo(n-2) end def each_with_ractor(enum, &block) env = Class.new env.define_singleton_method :call, &block enum.map do |v| Ractor.new(v, env) do |v, env| env.call(v) end end.map(&:take) end pp each_with_ractor([39]*20) { |n| fibo n }
parallel gem 的なノリで Ractor で each するコードを書いてみた。
env = Class.new
しているのは、Proc を Ractor に送り込むため。
単純に block
をそのまま送っていないのは、ProcオブジェクトはRactorに送れないため。
ClassクラスのオブジェクトはRactorのチェックをすり抜けるという便利さがあるので、なんとでもできるような気がする。
……と思っていたのだけど、単にRactor.new(v, &block)
でもだいたいのケースでは良さそう。
ただし、blockが外側のmutableな変数を参照していると死ぬ。
class C a = '' define_method :a do a end end 10000.times.map do Ractor.new do C.new.a << 1 end end.each(&:take) p C.new.a.size
RactorでRubyが壊れるコード。結果が10000にならなかったり、double freeになったり、いろんなエラーが出る。
ruby-jp の #concurrency で話していて、Ractor のバグではという話をしている
Ractor.allocate.nandemo_iikara_method_yobidashi
RactorでRubyが壊れるコード。その2
かならずSegmentation faultする