Ruby 1.9.2 リファレンスマニュアル > ライブラリ一覧 > 組み込みライブラリ > Fiberクラス
class Fiber
クラスの継承リスト: Fiber < Object < Kernel < BasicObject
Abstract
ノンプリエンプティブな軽量スレッド(以下ファイバーと呼ぶ)を提供します。 他の言語では coroutine あるいは semicoroutine と呼ばれることもあります。 Thread と違いユーザレベルスレッドとして実装されています。
Thread クラスが表すスレッドと違い、明示的に指定しない限り ファイバーのコンテキストは切り替わりません。 またファイバーは親子関係を持ちます。Fiber#resume を呼んだファイバーが親になり 呼ばれたファイバーが子になります。親子関係を壊すような遷移(例えば 自分の親の親のファイバーへ切り替えるような処理)はできません。 例外 FiberError が発生します。 できることは
- Fiber#resume により子へコンテキストを切り替える
- Fiber.yield により親へコンテキストを切り替える
の二通りです。この親子関係は動的なものであり 親ファイバーへコンテキストを切り替えた時点で解消されます。
なお標準添付ライブラリ fiber を require することにより、 コンテキストの切り替えに制限のない Fiber#transfer が使えるようになります。 任意のファイバーにコンテキストを切り替えることができます。
ファイバーが終了するとその親にコンテキストが切り替わります。
例外
ファイバー実行中に例外が発生した場合、親ファイバーに例外が伝播します。
例:
f = Fiber.new do raise StandardError, "hoge" end begin f.resume # ここでも StandardError が発生する。 rescue => e p e.message #=> "hoge" end
ショートチュートリアル
ファイバーは処理のあるポイントで他のルーチンにコンテキストを切り替え、またそのポイントから再開する という目的のために使います。 Fiber.new により与えられたブロックとともにファイバーを生成します。 生成したファイバーに対して Fiber#resume を呼ぶことによりコンテキストを切り替えます。 子ファイバーのブロック中で Fiber.yield を呼ぶと親にコンテキストを切り替えます。 Fiber.yield の引数が、親での Fiber#resume の返り値になります。
f = Fiber.new do n = 0 loop do Fiber.yield(n) n += 1 end end 5.times do p f.resume end #=> 0 1 2 3 4
以下は内部イテレータを外部イテレータに変換する例です。 実際 Enumerator は Fiber を用いて実装されています。
def enum2gen(enum) Fiber.new do enum.each{|i| Fiber.yield(i) } end end g = enum2gen(1..100) p g.resume #=> 1 p g.resume #=> 2 p g.resume #=> 3
注意
Thread クラスが表すスレッド間をまたがるファイバーの切り替えはできません。 例外 FiberError が発生します。
f = nil Thread.new do f = Fiber.new{} end.join f.resume #=> t.rb:5:in `resume': fiber called across threads (FiberError) from t.rb:5:in `<main>'
特異メソッド
new {|obj| ... } -> Fiber
-
与えられたブロックとともにファイバーを生成して返します。 ブロックは Fiber#resume に与えられた引数をその引数として実行されます。
ブロックが終了した場合は親にコンテキストが切り替わります。 その時ブロックの評価値が返されます。
a = nil f = Fiber.new do |obj| a = obj :hoge end b = f.resume(:foo) p a #=> :foo p b #=> :hoge
yield(*arg = nil) -> object
-
現在のファイバーの親にコンテキストを切り替えます。
コンテキストの切り替えの際に Fiber#resume に与えられた引数を yield メソッドは返します。
- [PARAM] arg:
- 現在のファイバーの親に渡したいオブジェクトを指定します。
- [EXCEPTION] FiberError:
- Fiber でのルートファイバーで呼ばれた場合に発生します。
例:
a = nil f = Fiber.new do a = Fiber.yield() end f.resume() f.resume(:foo) p a #=> :foo
インスタンスメソッド
resume(*arg = nil) -> object
-
自身が表すファイバーへコンテキストを切り替えます。 自身は resume を呼んだファイバーの子となります。
コンテキストの切り替えの際に Fiber.yield に与えられた引数を resume メソッドは返します。
- [PARAM] arg:
- self が表すファイバーに渡したいオブジェクトを指定します。
- [EXCEPTION] FiberError:
- 自身が既に終了している場合、コンテキストの切替が Thread クラスが表すスレッド間をまたがる場合、自身が resume を 呼んだファイバーの親かその祖先である場合に発生します。
例:
f = Fiber.new do Fiber.yield(:hoge) end a = f.resume() f.resume() p b #=> :hoge
追加されるメソッド
alive? -> bool
[added by fiber]-
ファイバーが「生きている」時、真を返します。
このメソッドが真を返すのは以下の場合です。
- まだ Fiber#resume されていない
- ブロック内の評価が終了していない (Fiber.yield が呼ばれていない)
例:
fr = Fiber.new{ Fiber.yield "a" } p fr.alive? # => true fr.resume # Fiber.yieldで戻ってくる p fr.alive? # => true fr.resume # ブロック内の評価を終えて戻ってくる p fr.alive? # => false
current -> Fiber
[added by fiber]-
このメソッドが評価されたコンテキストにおける Fiber のインスタンスを返します。
例:
fr = Fiber.new do Fiber.current end fb = fr.resume p fb.equal?(fr) # => true p Fiber.current # => #<Fiber:0x91345e4> p Fiber.current # => #<Fiber:0x91345e4>
transfer(*args) -> object
[added by fiber]-
自身が表すファイバーへコンテキストを切り替えます。
自身は Fiber#resume を呼んだファイバーの子となります。 Fiber#resume との違いは、ファイバーが終了したときや Fiber.yield が呼ばれたときは、 ファイバーの親へ戻らずにメインファイバーへ戻ります。
- [PARAM] args:
- メインファイバーから呼び出した Fiber#resume メソッドの返り値として渡したいオブジェクトを指定します。
- [RETURN]
- コンテキスト切り替えの際に、Fiber#resume メソッドに与えられた引数を返します。
- [EXCEPTION] FiberError:
- 自身が既に終了している場合、コンテキストの切り替えが Thread クラスが表すスレッド間をまたがる場合、 Fiber#resume を呼んだファイバーがその親か先祖である場合に発生します。
例:
require 'fiber' fr1 = Fiber.new do |v| :fugafuga end fr2 = Fiber.new do |v| fr1.transfer :fuga end fr3 = Fiber.new do |v| fr2.resume :hoge end p fr3.resume # => :fugafuga