2

URL への同期要求を行うことができる Ruby で記述された Http クライアントがあります。しかし、複数のリクエストをすばやく実行するために、Eventmachine を使用することにしました。アイデアは、すべてのリクエストをキューに入れ、eventmachine を使用してそれらを実行することです。

class EventMachineBackend
  ...
  ...
  def execute(request)
    $q ||= EM.Queue.new
    $q.push(request)
    $q.pop {|request| request.invoke}
    EM.run{EM.next_tick {EM.stop}}
  end
  ...
end

グローバル キュー変数の使用を許してください。後でリファクタリングします。EventMachineBackend#executeEventmachine キューを使用する正しい方法で行っていることはありますか?

私の実装で見られる 1 つの問題は、それが本質的に同期的であることです。リクエストをプッシュし、ポップしてリクエストを実行し、完了するのを待ちます。

誰でもより良い実装を提案できますか。

4

1 に答える 1

10

EventMachine と連携するには、リクエスト ロジックを非同期にする必要があります。 em-http-requestを使用することをお勧めします。ここで使用方法の例を見つけることができます。リクエストを並行して実行する方法を示しています。複数の接続を並行して実行するためのさらに優れたインターフェースは、同じ gemのMultiRequest クラスです。

リクエストをキューに入れ、一定数のリクエストのみを並行して実行したい場合は、次のようにすることができます:

EM.run do
  urls = [...] # regular array with URLs
  active_requests = 0

  # this routine will be used as callback and will
  # be run when each request finishes
  when_done = proc do
    active_requests -= 1
    if urls.empty? && active_requests == 0
      # if there are no more urls, and there are no active
      # requests it means we're done, so shut down the reactor
      EM.stop
    elsif !urls.empty?
      # if there are more urls launch a new request
      launch_next.call
    end
  end

  # this routine launches a request
  launch_next = proc do
    # get the next url to fetch
    url = urls.pop
    # launch the request, and register the callback
    request = EM::HttpRequest.new(url).get
    request.callback(&when_done)
    request.errback(&when_done)
    # increment the number of active requests, this
    # is important since it will tell us when all requests
    # are done
    active_requests += 1
  end

  # launch three requests in parallel, each will launch
  # a new requests when done, so there will always be 
  # three requests active at any one time, unless there
  # are no more urls to fetch
  3.times do
    launch_next.call
  end
end

emptor に注意してください。上記のコードで見逃した詳細がある可能性が非常に高いです。

私の例のロジックに従うのが難しいと思われる場合は、イベント プログラミングの世界へようこそ。読み取り可能なイベント コードを記述するのは非常に困難です。それはすべて後退します。最後から読み始めると役立つ場合もあります。

ダウンロードを開始した後にリクエストを追加したくないと思いましたが、質問のコードからはそう見えませんが、必要に応じてコードを書き直して、のEM::Queue代わりにを使用できます通常の配列であり、EM.stop停止しないため、 を行う部分を削除します。アクティブなリクエストの数を追跡するコードもおそらく削除できます。これは関係ないためです。重要な部分は次のようになります。

launch_next = proc do
  urls.pop do |url|
    request = EM::HttpRequest.new(url).get
    request.callback(&launch_next)
    request.errback(&launch_next)
  end
end

また、私のコードは実際には応答に対して何もしないことに注意してください。when_done応答はルーチンに引数として渡されます(最初の例)。成功とエラーに対しても同じことを行いますが、実際のアプリケーションではやりたくないかもしれません。

于 2011-02-14T18:59:35.117 に答える