Лучше использовать 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

Ответы на вопрос(1)

Ваш ответ на вопрос