EventMachine и зацикливание

Вот мой код:

EventMachine.run {

    conn = EM::Protocols::HttpClient2.connect request.host, 80

    req = conn.get(request.query)
    req.callback { |response|
      p(response.status)
      p(response.headers)
      p(response.content)
    }
}

Обратные вызовы срабатывают, то есть я получаю строковые выводы статуса и т.д.

Но я хочу, чтобы он запускал обратные вызовы, а затем повторял. Я планирую реализовать больше логики, например, каждый раз настраивать URL-адрес, но сейчас я просто хочу, чтобы это:

  1. Получить URL-адрес
  2. Активировать обратные вызовы
  3. Повторение...

Мое понимание этого шаблона заключалось в том, что все в этом цикле срабатывает, затем возвращается, затем продолжается вечно, пока я не сделаю EM.stop.

Прямо сейчас он извлекает данные URL и, кажется, просто зависает.

Нужно ли мне делать какой-то возврат, чтобы продолжить здесь? Почему он зависает, а не зацикливается снова и снова?

Если я окружу весь вышеприведенный блок кода циклом do... end, он будет работать, как и ожидалось... это правильный способ реализовать это? Полагаю, я сбит с толку, так как думал, что все внутри EM.run повторяется, когда оно завершается.


person Geremy    schedule 20.08.2012    source источник


Ответы (1)


Блок run, который вы даете, запускается только один раз. Цикл событий не отображается непосредственно для вас, а является чем-то, что должно быть невидимым. Не путайте блок run с циклом while. Он запускается один раз и только один раз, но запускается во время выполнения цикла обработки событий.

Если вы хотите повторить операцию, вам нужно создать какой-то стек и работать с ним, при этом каждый обратный вызов проверяет стек, есть ли еще работа, которую нужно выполнить, а затем выполняет другой вызов. Приложения EventMachine создаются с использованием этого метода связывания обратных вызовов.

Вам нужно будет реализовать что-то вроде:

def do_stuff(queue, request = nil)
  request ||= queue.pop
  return unless (request)

  conn = EM::Protocols::HttpClient2.connect request.host, 80

  req = conn.get(request.query)
  req.callback { |response|
    p(response.status)
    p(response.headers)
    p(response.content)

    EventMachine.next_tick do
      # This schedules an operation to be performed the next time through
      # the event-loop. Usually this is almost immediate.
      do_stuff(queue)
    end
  }
end   

Внутри вашего цикла событий вы запускаете эту цепочку:

EventMachine.run do
  queue = [ ... ] # List of things to do
  do_stuff(queue)
end

Вероятно, вы сможете найти более элегантный способ реализации этого, когда лучше поймете, как работает EventMachine.

person tadman    schedule 20.08.2012
comment
Точный ответ, который я искал. Большое спасибо! - person Geremy; 20.08.2012