红宝石纤维计划中的控制流程

时间:2016-09-16 22:04:38

标签: ruby fiber

我知道光纤是合作线程。光纤控制执行上下文,而抢先线程则不控制。光纤可以控制光纤,这意味着光纤可以在明确定义的位置开始和停止。

显然,纤维用于红宝石的原因是为了清理由反应器模式引起的嵌套块。

但是我很难掌握下面使用光纤的脚本的控制流程。

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)EM启动其事件循环

2)创建光纤然后调用简历。传递给new的代码块是否立即执行或者在调用resume之后执行它?

3)第一次调用http_get。它执行异步事件(在linux上使用select,poll或epoll)。我们设置了异步事件的事件处理程序(在回调方法中)。然后Fiber自动控制线程EventMachine打开(主线程)。但是,一旦调用回调,它将使用f.resume(http)进行控制。但是在这个简化的例子中,我应该在f.resume(http)之后放置我自己的回调代码吗?因为现在似乎f.resume(http)只是将控制返回到光纤而没有做任何事情。

我认为在yield之后发生的事情是控件进入EventMachine进入其事件循环。所以第二个http_get还没有被调用。现在一旦调用回调,然后控制返回到光纤(我们只使用一个Fiber.new,所以我假设所有这些中只有一个光纤实例)。但第二个http_get什么时候被调用?

1 个答案:

答案 0 :(得分:1)

让我看看能不能为你解答。我正在添加行号以帮助描述:

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. 第21行开始执行代码位于第14-20行
  2. 的光纤
  3. 光纤代码似乎在执行以下操作:第14行检查我们是否可以在google.come上执行GET。在第17行,它检查来自http_get的响应是否有效,然后在第18行执行下一个请求以搜索字符串eventmachine
  4. 当光纤执行因第21行的.resume而开始时,执行第14行,调用http_get方法。
  5. 第02行到第07行设置异步HTTP GET请求和回调。
  6. 第09行将控制权交还给EventMachine。
  7. 一段时间后,来自第03行的异步HTTP GET调用以异步方式完成执行并导致第06行或第07行的回调之一,在第13行到第20行创建的原始光纤返回控件。
  8. 现在,光纤执行从第15行恢复。来自第06/07行的回调已经传递了对http对象的引用,该对象现在在第14行中用变量page引用,随后在第15行中使用转储HTTP请求状态。
  9. 当光纤继续执行时,它会检查page是否为真值,然后继续并再次调用http_get,但使用新的URL。请注意,代码if page可能永远不会执行,因为它是nil,因为第15行会在没有page检查的情况下被nil访问的位置进行轰炸。
  10. 类似的过程重复 - 第02行到第07行设置HTTP GET调用,第09行将控制权交还给EventMachine。
  11. 一段时间后,调用其中一个回调,并在光纤重新获得控制权时执行第19行。
  12. 执行第19行后,光纤将会死亡。
  13. 希望澄清此事。

    至于使用附加逻辑处理HTTP GET的响应,我猜你可以用一些有意义的处理逻辑替换puts。此示例中的puts似乎处理响应,回调主要用于恢复光纤。