threadfiber - Thread による Fiber の実装

Thread を使って Fiber を模倣するライブラリを作ってみました。

require "threadfiber"
ThreadFiber.deploy

f = Fiber.new do
  p :foo
  Fiber.yield
  p :bar
end

f.resume  #=> :foo
p :hoge   #=> :hoge
f.resume  #=> :bar

1.9 の Fiber とちがって、Thread をまたいで Fiber が呼べます。

require "threadfiber"
ThreadFiber.deploy

f = Fiber.new do
  p :foo
  Fiber.yield
  p :bar
end

Thread.new { f.resume }.join  #=> :foo
Thread.new { f.resume }.join  #=> :bar

ただし複数のスレッドから同時に ThreadFiber#resume したら、片方に double resume (FiberError) が投げられます。ThreadFiber#resume_wait を使えば、その Fiber が yield されるまで待ちます。

1.8 でも動きます。1.8 で Fiber を試してみたい人にはいいかも。まあ僕は普段 1.9 しか使ってないので、知らないうちに動かなくなるかも知らないですけど。

$ ruby18 -v -e '
require "rubygems"
require "threadfiber"
ThreadFiber.new { p :foo }.resume
'
ruby 1.8.7 (2008-08-21 revision 18749) [i686-linux]
:foo

他に 1.9 の Fiber との違いは、

  • 遅い (1.9 の Fiber も速くはないけど、それよりも遅い)
  • Fiber#transfer がない (たぶんすぐ作れるけど、要らないと思うので)
  • root fiber では Fiber.current が nil を返す (面倒だった)
  • fiber の中と外でスレッド変数のスコープがちがう

くらいです。たぶん。

ソースはこちら。はじめての github

gem も公開してみたので、以下でインストールできるかもしれません。どうなっても知りませんけど。

$ gem install mame-threadfiber --source=http://gems.github.com
$ ruby -e '
require "rubygems"
require "threadfiber"
ThreadFiber.new { p :foo }.resume
'
:foo

ちなみに 1.8 で test/test_threadfiber.rb を動かすと SEGV しますが、threadfiber は pure Ruby なので、どうみても 1.8 のバグです。callcc と thread と gc の絡んだ問題っぽくてデバッグしたくないので、見なかったことに。