1

一連の を指定された順序で実行したいと考えてProcいます (つまり、非同期で実行することはできません)。それらのいくつかは、任意に長い時間がかかる場合があります。

私のコードは、EventMachine リアクタのコンテキスト内で実行されています。メインリアクタをブロックせずにこの種のコードを書くための既知のイディオムはありますか?

4

2 に答える 2

3

@maniacalrobot が言ったように、を使用するとEM.defer/deferrable、reactor をブロックすることなく proc を実行できます。しかし、複数のプロシージャを連続して実行する必要がある場合は、「コールバック地獄」に入ります。

私は、コードを読みやすくするための 2 つの解決策を知っています。プロミスとファイバーです。

Promisesは、非同期呼び出しを作成するための優れた API を提供します。以下を含む多くの優れた記事があります。

ファイバーはより Ruby 固有のツールであり、非同期処理を行いながらコードを同期的に見せることができます。

以下は、proc を非同期的に (遅延して) 実行するヘルパー メソッドですが、メインのリアクターをブロックせずに呼び出し元のコードをブロックします (これがファイバーの魔法です)。

def deferring(action)
  f = Fiber.current

  safe_action = proc do
    begin
      res = action.call
      [nil, res]
    rescue => e
      [e, nil]
    end
  end

  EM::defer(safe_action, proc { |error, result| f.resume([error, result]) })

  error, result = Fiber.yield

  raise error if error

  result
end

使用例:

action1_res = deferring(proc do 
  puts 'Async action 1'
  42
end

begin
  deferring(proc do
    puts "Action1 answered #{action1_res}"
    raise 'action2 failed'
  end)
rescue => error
  puts error
end
于 2014-02-21T07:06:21.213 に答える
0

通常はリア​​クタのメイン ループをブロックするコードは、 を使用して実行する必要がありますEM#deferEM#deferは引数として 2 つのブロックを取り、最初のブロックは別のスレッドで実行され、リアクターをブロックするべきではありません。オプションの 2 番目のブロックを渡すことができます。このブロックは、最初のブロックが完了すると呼び出されます (最初のブロックの結果も受け取ります)。

さらに読むhttps://github.com/eventmachine/eventmachine/wiki/EM::Deferrable-and-EM.defer

2 つの長時間実行オペレーションを連鎖させる例は、次のようになります。

logic_block = Proc.new { long_running_operation }
callback = Proc.new { |long_running_operation_result| EM.defer next_long_running_operation }

EM.defer logic_block, callback

2 番目の (コールバック) ブロックは、リアクター ループで実行されるため、実行時間の長いコードの複数のブロックを一緒にチェーンする予定がある場合は、コールバック内で EM.defer を再度呼び出す必要があることに注意してください。

于 2014-02-14T13:48:06.227 に答える