Ruby/Rubyの基礎知識

Fiberによる協調的な並行プログラミング(2ページ目)

ノンプリエンプティブな軽量スレッドであるFiberを紹介し、その基本的な使い方、およびFiber#transferを用いた制限のないコンテキスト切り替えを解説します。

橋本 拓也

執筆者:橋本 拓也

Rubyガイド

Fiberの基本的な使い方

それでは、Fiberクラスの挙動を観察してみてみましょう。Fiberは標準クラスなのでrequireは必要ありません。

Fiber.newするときには、Threadと同じくブロックを渡す必要があります。作成したFiberインスタンスはresumeメソッドを持ち、これを呼び出すとブロックが実行されます。

ただ「ブロックのコードを任意の場所で呼び出せる」だけではProcと変わりません。Fiber.yieldとresumeを組み合わせるのが、Fiberの真の使い方です(ただのyieldではなくFiberクラスのクラスメソッドFiber.yieldであることに注意してください)。

Fiber#resumeを呼び出すと子ファイバーにコンテキストを切り替え、ブロック中でFiber.yieldした時点でまた親にコンテキストを切り替えます。再度resumeすると前回の続きからブロックの処理が始まり、またFiber.yieldで親に戻ってきます。親と子がキャッチボールのように処理を切り替え、「協調的に」動作しています。

また、fiberをresumeできるのは「yieldの数+1回」であり、さらにresumeしようとするとFiberErrorが発生し"dead fiber called"だと怒られることもわかります。

状態を変えながらloopの中で無限にFiber.yieldを呼べるようにすれば、以下のような使い方も可能です。Fiberを用いて、resumeするたびにフィボナッチ数を順々に返すオブジェクトを作っています。

このように「計算を途中までで止めて部分的な結果を返し、また続きから計算を再開する」ようなモノを ジェネレータ と呼びます。FiberはRubyでジェネレータを実装する際の有力な手札となります。

ここまでを踏まえ、再びリファレンスマニュアルから引用します。

Thread クラスが表すスレッドと違い、明示的に指定しない限り ファイバーのコンテキストは切り替わりません。 またファイバーは親子関係を持ちます。Fiber#resume を呼んだファイバーが親になり 呼ばれたファイバーが子になります。親子関係を壊すような遷移(例えば 自分の親の親のファイバーへ切り替えるような処理)はできません。 例外 FiberError が発生します。 できることは

  • Fiber#resume により子へコンテキストを切り替える
  • Fiber.yield により親へコンテキストを切り替える

の二通りです。

class Fiber | Ruby 2.1.0 リファレンスマニュアル

Fiberは親子関係を持ち、親からはresume、子からはFiber.yieldという非対称な呼び出し関係にあるため、コルーチンではなくセミコルーチンと呼んだほうが正確です。

最後のページでは、非対称な親子関係に制限されない、Fiber#transferメソッドの使い方を解説します。

  • 前のページへ
  • 1
  • 2
  • 3
  • 次のページへ

あわせて読みたい

あなたにオススメ

    表示について

    カテゴリー一覧

    All Aboutサービス・メディア

    All About公式SNS
    日々の生活や仕事を楽しむための情報を毎日お届けします。
    公式SNS一覧
    © All About, Inc. All rights reserved. 掲載の記事・写真・イラストなど、すべてのコンテンツの無断複写・転載・公衆送信等を禁じます