ruby-fiber程序中的控制流

ruby-fiber程序中的控制流,ruby,fiber,Ruby,Fiber,我知道光纤是协作线程。光纤可以控制执行上下文,而抢占式线程则不能。光纤可以产生控制,这意味着光纤可以在定义明确的位置启动和停止 显然,在evented ruby中使用光纤的原因是为了清理由反应器模式引起的嵌套块 但我很难掌握下面使用光纤的脚本的控制流 def http_get(url) f = Fiber.current http = EventMachine::HttpRequest.new(url).get # resume fiber once http call is do

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

显然,在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)。我们设置异步事件的事件处理程序(在回调方法中)。然后,当机器打开(主线程)时,自动将控制权交给线程。但是,一旦调用回调函数,它就会用f.resume(http)重新控制。但在这个简化的示例中,我是否应该在f.resume(http)之后放置自己的回调代码?因为现在看来f.resume(http)只是将控制权返回到光纤,而不做其他事情


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

让我看看是否能帮你回答。我正在添加行号以帮助描述:

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
  • 第21行开始执行代码位于第14-20行的光纤
  • 光纤代码似乎在做以下工作:第14行检查我们是否可以进入
    google.come
    。在第17行,它检查是否有来自
    http_get
    的有效响应,然后在第18行执行下一个请求以搜索字符串
    eventmachine
  • 当光纤执行由于第21行的
    .resume
    而开始时,将执行第14行,该行调用
    http_get
    方法
  • 第02到07行设置异步HTTP GET请求和回调
  • 第09行将控制返回给EventMachine
  • 当来自第03行的异步HTTP GET调用异步完成执行并导致第06行或第07行的回调时,在第13行到第20行创建的原始光纤将恢复控制
  • 现在,光纤执行从第15行恢复。第06/07行的回调传递了对
    http
    对象的引用,该对象现在在第14行中被变量
    page
    引用,随后在第15行中用于转储http请求状态
  • 随着Fiber继续执行,它会检查
    页面
    是否为真实值,然后继续调用
    http\u get
    ,但使用新的URL。请注意,如果页面
    nil
    ,则代码
    可能永远不会执行,因为第15行在未检查
    nil
    的情况下会轰炸
    page
    访问的位置
  • 类似的过程重复-第02行到第07行设置HTTP GET调用,第09行将控制权返回给EventMachine
  • 一段时间后,调用其中一个回调,并在光纤恢复控制时执行第19行
  • 执行第19行后,光纤将断开
  • 希望这能澄清问题


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

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