更好地使用EM.next_tick或EM.defer来使用Eventmachine进行长时间运行的计算吗? [英] Better use EM.next_tick or EM.defer for long running calculation with Eventmachine?

查看:102
本文介绍了更好地使用EM.next_tick或EM.defer来使用Eventmachine进行长时间运行的计算吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我要弄清楚当我必须自己实现的长时间运行的计算时,如何利用可延期付款.对于我的示例,我想计算前200000斐波那契数,但仅返回某个数.

I am trying to figure out how to make use of deferrables when it comes to long running computations that I have to implement on my own. For my example I want to calculate the first 200000 Fibonacci numbers but return only a certain one.

我第一次尝试延期是这样的:

My first attempt of a deferrable looked like so:

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,否则一切都在一个系统线程内运行).因此,我想出了第二种尝试,对我来说似乎更好,特别是由于不同的回调绑定机制和不同线程的使用.

Only to realize that everything seemed to work pretty well, but the thread the deferrable runs in is the same as the reactor thread (knowing that everything runs inside one system thread unless rbx or jruby are used). So I came up with a second attempt that seems nicer to me, especially because of different callback binding mechanism and the use of different threads.

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

我应该首选哪种实现?都错了吗?还有另一个更好的吗?

Which one is the implementation that I should prefer? Are both wrong? Is there another, a better one?

更有趣的是:第二种尝试是否是在不阻塞反应堆的情况下实现我想要的任何东西(I/O op除外)的完美方法?

Even more interesting: Is the second attempts a perfect way to implement whatever I want (except I/O op's) without blocking the reactor?

推荐答案

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

Definitely EM.defer (or Thread.new I suppose), doing a long-running calculation in EM.next_tick will block your reactor for other things.

通常,您不希望反应堆中运行的任何块都长时间运行,无论它是否正在发生IO阻塞或整个应用程序停止运行.

As a general rule, you don't want ANY block running inside reactor to be running for long regardless if it is or isn't IO blocking or the entire app halts while this is happening.

这篇关于更好地使用EM.next_tick或EM.defer来使用Eventmachine进行长时间运行的计算吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆