繊維は私にとって比較的新しい概念です。各ファイバーのスタック サイズが 4kB に制限されていることを認識しており、これに「注意」する必要があることを読み続けています。この制限の実際の結果は正確には何ですか?
編集:
結局、この 4kB の制限はそれほど障害にはならないようで、SystemStackError を発生させるにはファイバー自体の内部にかなりの数 (4,045) のローカル変数が必要です。
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 回目の反復では平均して 1 秒あたり約 1 回の反復になります。5,100 回を少し超えた時点で実行を終了したため、RBX に制限があるかどうかはわかりません。また、RBX は MRI 1.9.3 の数倍のメモリを使用しています。
JRuby 1.7 では、ファイバーのスタック サイズが 4kB に設定されていないようです。また、ファイバーに最大スタック サイズがあるかどうかは不明です。最初のコード例の 5,000 回の反復を問題なく完了しましたが、予想どおり、JVM は数百 MB の RAM を食い尽くしました。