我试图了解以下代码段的行为.我特别关注的是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
Run Code Online (Sandbox Code Playgroud)
我已经编写了代码行,并在右侧执行了预期的执行顺序.一旦fiber3.resume返回并且我打电话fiber2.resume,我希望执行继续在fiber2标记为#10的行内.相反,我收到以下错误:
fiber2.rb:24:in `resume': cannot resume transferred Fiber (FiberError)
from fiber2.rb:24:in `<main>'
Run Code Online (Sandbox Code Playgroud)
这是从列表的最后一行报告的错误:fiber2.resume.
自 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
Run Code Online (Sandbox Code Playgroud)
目前的用例#transfer似乎是当您有两条光纤(我们称它们为 A 和 B)并且想要从 A 到 B,并且您不打算在 B 完成之前返回 A 时。然而,Ruby 没有尾部调用优化的概念,因此 A 仍然必须等待 B 完成并产生其最终值。尽管如此,#transfer现在本质上是一张单程票。
| 归档时间: |
|
| 查看次数: |
191 次 |
| 最近记录: |