首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >等待使用EventMachine和Ruby纤程进行异步调用

等待使用EventMachine和Ruby纤程进行异步调用
EN

Stack Overflow用户
提问于 2012-10-04 11:09:17
回答 1查看 3.9K关注 0票数 7

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

代码语言:javascript
复制
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的情况下重现this article中描述的em-synchrony样式的行为。)

编辑:下面是关于我最终想要完成的事情的更多细节。我正在开发一个在Thin上运行的Grape,在返回响应之前,每个路由处理程序都必须对数据存储、ZooKeeper、其他HTTP服务等进行各种顺序的调用。

em-synchrony真的很酷,但我总是遇到从根光纤产生的问题,或者结果显示上述情况的非同步症状。rack-fiber_pool似乎也有潜在的用处,但我不愿意使用它,因为它会破坏我所有的Rack::Test单元测试。

我将我的问题简化为上面的简单示例,因为我似乎对fibers和EventMachine应该如何一起使用有一个根本性的误解,这阻碍了我有效地使用更复杂的框架。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2012-10-04 11:39:14

你可能想要这样的东西:

代码语言:javascript
复制
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

这应该会产生以下结果:

代码语言:javascript
复制
A
(Async stuff happening)
B
C
D

更具概念性的解释:

纤程有助于解开异步代码,因为它们可以挂起和重新激活代码块,就像手动线程一样。这允许关于事情发生的顺序的巧妙技巧。下面是一个小示例:

代码语言:javascript
复制
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"之前运行),而“并行”纤程上的操作不能计算(也不应该关心)其他纤程上的操作是否已经执行:我们只能通过交换前两个resume调用来打印"BACD“。

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

这已经是一个冗长的答案,但如果仍然不清楚,我可以提供一个EventMachine示例(我知道这是一个难以理解的概念,我努力了很多)。

更新:我已经创建了一个示例,它可能会帮助任何还在为概念而苦苦挣扎的人:https://gist.github.com/renato-zannon/4698724。我建议你跑着玩它。

票数 9
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/12719781

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档