2016-07-05 9 views
4

次のコードスニペットの動作を理解しようとしています。私の具体的な焦点はFiber#transferメソッドです。Rubyファイバ:転送されたファイバの再開

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

ルビーのバグを発見した可能性があります。あなたがソースコードを見てみると、それはあなたがそれを記述する方法実装されます。転送フラグをフォロー

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

を、それはあなたが繊維の転送時に1に設定されているが、それはリセットされることはありません。

IMOファイバーゲインコントロール時、または歩留まりを呼び出すときにリセットする必要があります。

0

behavior has changed since Ruby 1.9と思われます。 1.9では、質問者が仮定する方法が機能し、Rubyの後のバージョンでは#transferの動作が変更されました。私は2.4でテストしていますが、これは2. *シリーズの以前のバージョンでも当てはまります。

1.9では、#transferは、ファイバ間で前後にジャンプするために使用できます。当時、#resumeはこの目的のために使用できなかった可能性があります。とにかく、Ruby 2.4のでは、#resumeを使用して1つのファイバから別のファイバにジャンプし、単に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のためのユースケースは、今、あなたは2本のファイバを持っているときのように見える(のは、AとB、それらを呼びましょう)とAから行きたいですあなたはBが終了する前にAに戻ることを計画していません。しかし、Rubyはテールコール最適化の概念を持っていないので、AはBが終了し最終値を返すのを待つ必要があります。それにもかかわらず、#transferは本質的に片道チケットです。

関連する問題