2016-09-16 3 views
2

Я знаю, что волокна являются кооперативными нитями. Волокно контролирует контекст выполнения, тогда как превентивный поток не работает. Волокно может давать контроль, что означает, что волокно может начинаться и останавливаться в четко определенных местах.управляющий поток в программе рубинового волокна

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

Но я с трудом пытаюсь понять поток управления приведенного ниже сценария, который использует волокно.

def http_get(url) 
    f = Fiber.current 
    http = EventMachine::HttpRequest.new(url).get 

    # resume fiber once http call is done 
    http.callback { f.resume(http) } 
    http.errback { f.resume(http) } 

    return Fiber.yield 
end 

EventMachine.run do 
    Fiber.new{ 
    page = http_get('http://www.google.com/') 
    puts "Fetched page: #{page.response_header.status}" 

    if page 
     page = http_get('http://www.google.com/search?q=eventmachine') 
     puts "Fetched page 2: #{page.response_header.status}" 
    end 
    }.resume 
end 

Я так понимаю:

1) ЭМ начинает свой цикл событий

2) Волокно создается, а затем резюме называется. Выполняется ли блок кода, переданный в новый, сразу же, или выполняется его после возобновления?

3) http_get называется в первый раз. Он выполняет асинхронное событие (используя select, poll или epoll для linux). Мы настроили обработчик события (в методе обратного вызова) асинхронного события. Затем Fiber добровольно дает управление потоку EventMachine включен (основной поток). Однако, как только будет вызван обратный вызов, он вернет управление с помощью f.resume (http). Но в этом упрощенном примере я должен поставить свой код обратного вызова после f.resume (http)? Потому что прямо сейчас кажется, что f.resume (http) просто возвращает управление волокну и ничего не делает.

Я думаю, что после выхода управление переходит к EventMachine, где он входит в цикл событий. Таким образом, второй http_get еще не вызывается. Теперь, когда обратный вызов вызывается, тогда управление возвращается в Fiber (мы используем только один Fiber.new, поэтому я предполагаю, что во всем этом есть только один экземпляр Fiber). Но когда вызывается второй http_get?

+0

Примечание к себе: при создании волокна оно не запускается автоматически. Скорее, это должно быть явно предложено работать с использованием метода возобновления Fiber #. – Donato

ответ

0

Позвольте мне посмотреть, могу ли я ответить на него за вас. Я добавляю номера строк, чтобы помочь описание:

01: def http_get(url) 
02: f = Fiber.current 
03: http = EventMachine::HttpRequest.new(url).get 
04: 
05: # resume fiber once http call is done 
06: http.callback { f.resume(http) } 
07: http.errback { f.resume(http) } 
08: 
09: return Fiber.yield 
10: end 
11: 
12: EventMachine.run do 
13: Fiber.new{ 
14:  page = http_get('http://www.google.com/') 
15:  puts "Fetched page: #{page.response_header.status}" 
16: 
17:  if page 
18:  page = http_get('http://www.google.com/search?q=eventmachine') 
19:  puts "Fetched page 2: #{page.response_header.status}" 
20:  end 
21: }.resume 
22: end 
  1. Line 21 начинает выполнение волокна, код которого в строках 14-20
  2. код Волокно, кажется, делает следующие: Строка 14 проверяет, является ли мы можем сделать GET на google.come. В строке 17 он проверяет, был ли действительный ответ от http_get, затем выполните следующий запрос в строке 18 для поиска строки eventmachine.
  3. Когда выполнение волокна начинается из-за .resume в строке 21, выполняется строка 14, которая вызывает метод http_get.
  4. Строка 02 - 07 устанавливает запрос асинхронного HTTP GET и обратные вызовы.
  5. Линия 09 возвращает управление в EventMachine.
  6. По истечении некоторого времени, когда асинхронный HTTP-вызов GET из строки 03 завершает выполнение асинхронно и приводит к одному из обратных вызовов в строке 06 или 07, исходное волокно, созданное в строке 13 по строке 20, возвращает элемент управления.
  7. Теперь выполнение Fiber возобновляется из строки 15. Обратный вызов из строки 06/07 передал ссылку на объект http, который теперь ссылается на переменную page в строке 14 и впоследствии используется в строке 15 для сброса статуса HTTP-запроса.
  8. Поскольку Fiber продолжает выполнение дальше, он проверяет, является ли значение page правдоподобным значением, затем идет дальше и снова вызывает http_get, но с новым URL.Обратите внимание, что код if page никогда не может быть выполнен в случае, если он был nil, поскольку Линия 15 бомбили бы там, где page был получен без проверки на nil.
  9. Аналогичные процессы повторяются - строка 02 - 07 устанавливает HTTP GET-вызов, а строка 09 возвращает управление EventMachine.
  10. Через некоторое время вызывается один из обратных вызовов, а строка 19 запускается как управление восстановлением волокна.
  11. После выполнения линии 19 волокно станет мертвым.

Надеюсь, что это прояснит вопрос.

Что касается обработки ответа HTTP GET с дополнительной логикой, я думаю, вы можете заменить puts на некоторую значимую логику обработки. puts в этом примере, похоже, имеет дело с ответами, а обратные вызовы используются в основном для возобновления волокна.