7

我在 Ruby 1.9.2 下运行这个代码片段:

require "eventmachine"
require "fiber"

EM.run do
  fiber = Fiber.new do
    current_fiber = Fiber.current
    EM.add_timer(2) do
      print "B"
      current_fiber.resume("D")
    end
    Fiber.yield
  end
  print "A"
  val = fiber.resume
  print "C"
  print val
  EM.stop
end

我期望输出是“ABCD”,程序在“A”之后暂停两秒钟。但是,它只是立即打印出“AC”,然后在退出之前等待两秒钟。我究竟做错了什么?

(作为参考,我试图在不使用 em-synchrony 的情况下重现本文中描述的 em-synchrony-style 行为。)

编辑:这里有一些关于我最终想要完成的更多细节。我正在开发一个在 Thin 上运行的 Grape API,每个路由处理程序必须在返回响应之前对数据存储、ZooKeeper、其他 HTTP 服务等进行一系列调用。

em-synchrony 真的很酷,但我一直遇到从根光纤屈服或结果显示上述情况的非同步症状的问题。rack-fiber_pool 似乎也可能有用,但我不愿意承诺使用它,因为开箱即用,它破坏了我所有的 Rack::Test 单元测试。

我将我的问题简化为上面的简单示例,因为我似乎对应如何一起使用纤维和 EventMachine 有一个基本的误解,这使我无法有效地使用更复杂的框架。

4

1 回答 1

9

你可能想要这样的东西:

require "eventmachine"
require "fiber"

def value
  current_fiber = Fiber.current

  EM.add_timer(2) do
    puts "B"
    current_fiber.resume("D") # Wakes the fiber
  end

  Fiber.yield # Suspends the Fiber, and returns "D" after #resume is called
end

EM.run do
  Fiber.new {
    puts "A"
    val = value
    puts "C"
    puts val

    EM.stop
  }.resume

  puts "(Async stuff happening)"
end

这应该会产生以下结果:

A
(Async stuff happening)
B
C
D

更概念性的解释:

纤维有助于解开异步代码,因为它们是要暂停和恢复的代码块,就像手动线程一样。这允许关于事情发生的顺序的巧妙技巧。一个小例子:

fiberA = Fiber.new {
  puts "A"
  Fiber.yield
  puts "C"
}

fiberB = Fiber.new {
  puts "B"
  Fiber.yield
  puts "D"
}

fiberA.resume # prints "A"
fiberB.resume # prints "B"
fiberA.resume # prints "C"
fiberB.resume # prints "D"

因此,当#resume在纤程上调用时,它会恢复执行,无论是从块的开头(对于新纤程)还是从先前的Fiber.yield调用开始,然后执行直到Fiber.yield找到另一个或块结束。

重要的是要注意,在纤程中放置一系列动作是一种说明它们之间时间依赖关系的方式(puts "C"不能在之前运行puts "A"),而“并行”纤程上的动作不能指望(也不应该在意) about) 其他纤程上的操作是否已执行:我们将仅通过交换前两个resume调用来打印“BACD”。

所以,rack-fiber_pool它的魔力是这样的:它将你的应用程序接收到的每个请求都放在一个纤程中(这意味着顺序无关),然后期望你执行Fiber.yieldIO 操作,以便服务器可以接受其他请求。然后,在 EventMachine 回调中,您传入一个包含 a 的块current_fiber.resume,以便在查询/请求/任何内容的答案准备好时重新激活您的光纤。

这已经是一个冗长的答案,但是如果仍然不清楚,我可以提供一个 EventMachine 示例(我知道这是一个令人毛骨悚然的概念,我很挣扎)。


更新:我创建了一个示例,可以帮助任何仍在为这些概念苦苦挣扎的人:https ://gist.github.com/renato-zannon/4698724 。我建议运行和玩它。

于 2012-10-04T03:39:13.713 回答