我试图了解以下代码段的行为。我特别关注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
,我预计执行将在fiber2
内的标记为#10 的行继续。相反,我收到以下错误:
fiber2.rb:24:in `resume': cannot resume transferred Fiber (FiberError)
from fiber2.rb:24:in `<main>'
这是从商家信息的最后一行报告的错误:fiber2.resume
。
答案 0 :(得分:3)
似乎是behavior has changed since 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时,你不打算再回到A B完成。但是,Ruby没有尾调用优化的概念,所以A仍然需要等待B完成并产生它的最终值。尽管如此, #transfer
现在基本上是一张单程票。
答案 1 :(得分:2)
您可能在ruby中发现了一个错误。当您查看源代码时,它将按您描述的方式实现:
https://fossies.org/linux/misc/ruby-2.3.1.tar.gz/ruby-2.3.1/cont.c
按照传输的标志,当您传输光纤时它被设置为1,但它永远不会被重置。
IMO应在光纤增益控制或调用良率时复位。