最好使用EM.next_tick或EM.defer与Eventmachine进行长时间运行计算?

我试图弄清楚如何在我必须自己实现的长时间运行的计算中使用延迟。 对于我的例子,我想计算前200000个斐波纳契数,但只返回一个。

我对延期的第一次尝试看起来像这样:

class FibA include EM::Deferrable def calc m, n fibs = [0,1] i = 0 do_work = proc{ puts "Deferred Thread: #{Thread.current}" if i < m fibs.push(fibs[-1] + fibs[-2]) i += 1 EM.next_tick &do_work else self.succeed fibs[n] end } EM.next_tick &do_work end end EM.run do puts "Main Thread: #{Thread.current}" puts "#{Time.now.to_i}\n" EM.add_periodic_timer(1) do puts "#{Time.now.to_i}\n" end # calculating in reactor thread fib_a = FibA.new fib_a.callback do |x| puts "A - Result: #{x}" EM.stop end fib_a.calc(150000, 21) end 

只是意识到一切似乎都运行得很好,但是延迟运行的线程与反应器线程相同(知道一切都在一个系统线程内运行,除非使用rbx或jruby)。 所以我想出了第二次尝试对我来说更好,特别是因为不同的回调绑定机制和使用不同的线程。

 class FibB include EM::Deferrable def initialize @callbacks = [] end def calc m, n work = Proc.new do puts "Deferred Thread: #{Thread.current}" @fibs = 1.upto(m).inject([0,1]){ |a, v| a.push(a[-1]+a[-2]); a } end done = Proc.new do @callbacks.each{ |cb| cb.call @fibs[n]} end EM.defer work, done end def on_done &cb @callbacks << cb end end EM.run do puts "Main Thread: #{Thread.current}" puts "#{Time.now.to_i}\n" EM.add_periodic_timer(1) do puts "#{Time.now.to_i}\n" end # calculating in external thread fib_b = FibB.new fib_b.on_done do |res| puts "B - Result: #{res}" end fib_b.on_done do EM.stop end fib_b.calc(150000, 22) end 

哪一个是我更喜欢的实现? 都错了吗? 还有另一个更好的吗?

更有趣的是:第二次尝试是否是一种完美的方式来实现我想要的任何东西(I / O操作除外)而不会阻塞反应堆?

绝对是EM.defer(或者我认为是Thread.new),在EM.next_tick中进行长时间运行的计算会阻止你的反应堆进行其他操作。

作为一般规则,您不希望在reactor内运行的任何块在很长时间内运行,无论它是否是IO阻塞,或者整个应用程序在发生这种情况时停止运行。