Ruby纤程:恢复传输的纤程

5

我正在尝试理解以下代码片段的行为。 我特别关注Fiber#transfer方法。

require 'fiber'

fiber2 = nil

fiber1 = Fiber.new do
  puts "In Fiber 1"                 # 3
  fiber2.transfer                   # 4
end

fiber2 = Fiber.new do
  puts "In Fiber 2"                  # 1
  fiber1.transfer                    # 2
  puts "In Fiber 2 again"            # 5
  Fiber.yield                        # 6
  puts "Fiber 2 resumed"             # 10
end

fiber3 = Fiber.new do
  puts "In Fiber 3"                  # 8
end

fiber2.resume                        # 0
fiber3.resume                        # 7
fiber2.resume                        # 9

我已经按照预期的代码执行顺序在右边对代码行进行了编号。一旦fiber3.resume返回并且我调用fiber2.resume,我期望执行将在标有# 10的行内继续在fiber2中进行。但是,我遇到了以下错误:

fiber2.rb:24:in `resume': cannot resume transferred Fiber (FiberError)
    from fiber2.rb:24:in `<main>'

这是来自清单最后一行的错误报告:fiber2.resume

2个回答

4

看起来自 Ruby 1.9 以来,行为已经发生了变化。在1.9中,事情的处理方式与问题提问者所假设的方式相同,但是Ruby的后续版本改变了#transfer的工作方式。我正在2.4上进行测试,但这也适用于2.*系列较早的版本。

在1.9中,#transfer可用于在纤程之间跳来跳去。可能当时#resume不能用于此目的。无论如何,在Ruby 2.4中,您可以使用#resume从一个纤程跳转到另一个纤程,然后简单地使用Fiber.yield()跳回到调用方。

示例(基于问题中的代码):

require 'fiber'

fiber2 = nil

fiber1 = Fiber.new do
  puts "In Fiber 1"                 # 3
  Fiber.yield                       # 4 (returns to fiber2)
end

fiber2 = Fiber.new do
  puts "In Fiber 2"                  # 1
  fiber1.resume                      # 2
  puts "In Fiber 2 again"            # 5
  Fiber.yield                        # 6 (returns to main)
  puts "Fiber 2 resumed"             # 10
end

fiber3 = Fiber.new do
  puts "In Fiber 3"                  # 8
end

fiber2.resume                        # 0
fiber3.resume                        # 7
fiber2.resume                        # 9

#transfer 的使用场景现在似乎是当你有两个纤程(我们称其为 A 和 B)并希望从 A 到 B,而且不打算在 B 完成之前返回 A。然而,Ruby 没有尾调用优化的概念,所以 A 仍然必须等待 B 完成并产生其最终值。尽管如此,#transfer 现在基本上是单向票。


2
你可能在 Ruby 中发现了一个 bug。当你查看源代码时,它的实现方式与你所描述的方式相同。

https://fossies.org/linux/misc/ruby-2.3.1.tar.gz/ruby-2.3.1/cont.c

跟随传输的标志,当你转移光纤时它被设置为1但从未重置。
在我看来,当光纤增益控制或调用产量时应该将其重置。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接