忍んでいる肉球の足跡

プログラムに関連することを雑多に扱います

RailsでPromisesやFutureを使う方法

共通して注意すること

  • 並列処理中に動的クラス解決させない
  • value!を使う

並列処理中に動的クラス解決させない

Concurrent::Promises.future 内部で動的クラス解決を行おうとすると、
Circular dependency detected while autoloading constant というエラーが出てしまう。

回避策としては事前にRails.application.executor.wrapの前でMyClassを宣言して動的クラス解決を事前にさせること。

MyClass
Rails.application.executor.wrap do
  Concurrent::Promises.future do 
    MyClass.async_something
  end
end

value!を使う

参考のところにも書いてあるが、value!を利用しないとエラーハンドリングから漏れることに注意。

Promises.future

※プロセス数管理は勝手にやってくれるやつ
※eachだか lazyだかで大量に回そうとするとプロセスが作れなくなるのかセグフォするので注意↓
※(version ruby 2.5.3, rails 5.0?)

Rails.application.executor.wrap do
  Concurrent::Promises.future do 
    :async_something
  end
end

ActiveSupport::Dependencies.interlock.permit_concurrent_loads do 
  Concurrent::Promises.zip(*tasks).value!
end

Future.execute

※ こちらはプロセス数に個数制限を掛けられるのでeachやlazyで雑に回せる

thread_pool  = Concurrent::FixedThreadPool.new(20)
Rails.application.executor.wrap do
  Concurrent::Future.execute({ executor: thread_pool }), do 
    :async_something
  end
end

ActiveSupport::Dependencies.interlock.permit_concurrent_loads do 
  executors.map(&:value!)
end

参考: