纤维对我来说是一个相对较新的概念。我知道每根光纤的堆栈大小限制为 4kB,我一直在读我应该“提防”这一点。这个限制对现实世界的影响究竟是什么?
编辑:
看起来这个 4kB 的限制毕竟不是一个障碍,它需要光纤本身内的大量局部变量 (4,045) 才能引发 SystemStackError。
count = 0
loop do
count += 1
puts count
varlist = String.new
count.times do |i|
varlist += "a#{i} = 1\n"
end
s = "fiber = Fiber.new do \n #{varlist} \n end \n fiber.resume"
eval(s)
end
不是最优雅的代码,但它似乎证明了光纤堆栈的局限性。似乎它只是返回值、局部变量(所有这些都包含对堆上对象的引用)和方法调用被放入堆栈。我没有测试从光纤调用的方法中的局部变量等是否是光纤堆栈的一部分。
编辑2:
修改了上面的代码。看起来被调用方法中的变量等成为了光纤堆栈的一部分。如果是这种情况,那么调用深度(即使没有递归)可能会成为一个更大的问题,因为方法本身可能需要比变量更多的堆栈空间(这似乎是对堆上对象的透明引用)。
以下代码在第 4,031 次迭代中失败,并表明被调用方法中的变量成为光纤堆栈的一部分:
count = 0
loop do
count += 1
puts count
varlist = String.new
count.times do |i|
varlist += "a#{i} = 1\n"
end
m = "def meth\n #{varlist} \n end"
eval(m)
fiber = Fiber.new do
meth
end
fiber.resume
end
编辑3:
刚刚尝试在 Rubinius 2.0 上运行初始代码示例。它的纤维似乎没有 4kB 的堆栈限制,尽管超过大约 3,500 次迭代它变得越来越慢,并且在大约 5,000 次迭代时它平均每秒迭代一次。我不知道 RBX 是否有限制,因为我在超过 5,100 次迭代时退出了执行。RBX 使用的内存也比 MRI 1.9.3 多几倍。
JRuby 1.7 似乎也没有 4kB 的光纤堆栈大小,如果光纤有最大堆栈大小,我不知道。我完成了第一个代码示例的 5,000 次迭代,没有出现任何问题,尽管正如可以预料的那样,JVM 消耗了几百 MB 的 RAM。