bre*_*ker 7 ruby eventmachine fibers
我在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
Run Code Online (Sandbox Code Playgroud)
我期待输出为"ABCD",程序在"A"后暂停两秒钟.但是,它只是立即打印出"AC",然后在退出前等待两秒钟.我究竟做错了什么?
(作为参考,我试图在不使用em-synchrony的情况下重现本文中描述的em-synchrony风格的行为.)
编辑:这里有一些关于我最终要完成的事情的更多细节.我正在开发一个在Thin上运行的Grape API,并且每个路由处理程序必须在返回响应之前对数据存储,ZooKeeper,其他HTTP服务等进行各种串行调用.
em-synchrony真的很酷,但是我一直遇到从根光纤屈服或结果显示上述情况的非同步症状的问题.rack-fiber_pool似乎也很有用,但我不愿意使用它,因为开箱即用它会破坏我所有的Rack :: Test单元测试.
我将问题简化为上面的简单示例,因为我似乎对如何一起使用光纤和EventMachine存在根本的误解,这阻碍了我有效地使用更复杂的框架.
你可能想要这样的东西:
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
Run Code Online (Sandbox Code Playgroud)
这应该产生以下结果:
A
(Async stuff happening)
B
C
D
Run Code Online (Sandbox Code Playgroud)
一个更概念性的解释:
Fibers帮助解开异步代码,因为它们的代码块被暂停和恢复,就像手动线程一样.这允许有关事情发生顺序的巧妙技巧.一个小例子:
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"
Run Code Online (Sandbox Code Playgroud)
因此,当#resume在光纤上调用时,它会从块的开头(对于新光纤)或之前的Fiber.yield调用恢复执行,然后执行直到Fiber.yield找到另一个或块结束.
重要的是要注意,在光纤内部放置一系列动作是一种表达它们之间的时间依赖性的方式(puts "C"以前不能运行puts "A"),而"并行"光纤上的动作不能指望(并且不应该关注)关于其他光纤上的动作是否已执行:我们只能通过交换前两个resume调用来打印"BACD" .
因此,rack-fiber_pool它的神奇之处在于:它将您的应用程序接收的每个请求放在光纤中(这意味着顺序无关),然后期望您进行Fiber.yieldIO操作,以便服务器可以接受其他请求.然后,在EventMachine回调中,传入一个包含a的块current_fiber.resume,以便在查询/请求/其他任何内容准备就绪时,恢复光纤.
这已经是一个冗长的答案,但我可以提供一个EventMachine示例,如果它仍然不清楚(我认为这是一个毛茸茸的概念,我很努力).
更新:我已经创建了一个示例,可以帮助那些仍在努力解决这些概念的人:https://gist.github.com/renato-zannon/4698724.我建议跑步和玩它.