【问题标题】:control flow in ruby fiber programRuby Fiber 程序中的控制流程
【发布时间】:2016-09-16 22:04:37
【问题描述】:

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

显然,在 evented ruby​​ 中使用纤维的原因是为了清理由反应器模式引起的嵌套块。

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

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) 只是将控制权返回给 Fiber 而没有做任何其他事情。

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

【问题讨论】:

  • 自我注意:创建光纤时,它不会自动运行。相反,必须明确要求它使用 Fiber#resume 方法运行。

标签: ruby fiber


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

希望能澄清此事。

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

【讨论】:

    猜你喜欢
    • 2011-10-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-10
    • 1970-01-01
    • 1970-01-01
    • 2019-09-14
    相关资源
    最近更新 更多