Fibers

Ruby 1.9 introduces a new class called a Fiber, which is a bit like a thread and a bit like a block. Fibers are intended for the implementation of “lightweight concurrency.” This broadly means they operate like blocks (see Chapter 10) whose execution can be paused and restarted just as you can with threads. Unlike threads, however, the execution of fibers is not scheduled by the Ruby virtual machine; it has to be controlled explicitly by the programmer. Another difference between threads and fibers is that threads run automatically when they are created; fibers do not. To start a fiber, you must call its resume method. To yield control to code outside the fiber, you must call the yield method.

Let’s look at some simple examples:

fiber_test.rb

f = Fiber.new do
    puts( "In fiber" )
    Fiber.yield( "yielding" )
    puts( "Still in fiber" )
    Fiber.yield( "yielding again" )
    puts( "But still in fiber" )
end

puts( "a" )
puts( f.resume )
puts( "b" )
puts( f.resume )
puts( "c" )
puts( f.resume )
puts( "d" )
puts( f.resume )   # dead fiber called

Here I create a new fiber, f, but don’t immediately start it running. First I display “a”, puts( "a" ), and then I start the fiber, f.resume. The fiber starts executing and displays the “In fiber” message. But then it calls yield with the “yielding” string. This suspends the execution of the fiber and allows the code outside the fiber to continue. The code that called f.resume now puts the string that’s been yielded, so “yielding” is displayed. Another call to f.resume restarts the fiber where you left off, so “Still in fiber” is displayed, and so on. With each call to yield, execution returns to code outside the fiber. And, when that code calls f.resume, the remaining code in the fiber is executed. Once there is no more code left to be executed, the fiber terminates. When an inactive (or dead) fiber is called by f.resume, a FiberError occurs. This is the output from the program shown earlier:

a
In fiber
yielding
b
Still in fiber
c
But still in fiber
d
C:/bookofruby/ch17/fiber_test.rb:18:in `resume': dead fiber called (FiberError)
from C:/bookofruby/ch17/fiber_test.rb:18:in `<main>'

You can avoid “dead fiber” errors by testing the state of a fiber using the alive? method. This returns true if the fiber is active and returns false if inactive. You must require 'fiber' in order to use this method:

fiber_alive.rb

require 'fiber'

if (f.alive?) then
    puts( f.resume )
else
    puts("Error: Call to dead fiber" )
end

The resume method accepts an arbitrary number of parameters. On the first call to resume, they are passed as block arguments. Otherwise, they become the return value of the call to yield. The following example is taken from the documentation in the Ruby class library:

fiber_test2.rb

fiber = Fiber.new do |first|
    second = Fiber.yield first + 2
end

puts fiber.resume 10    #=> 12
puts fiber.resume 14    #=> 14
puts fiber.resume 18    #=> dead fiber called (FiberError)

Here’s a simple example illustrating the use of two fibers:

f = Fiber.new {
    | s |
    puts( "In Fiber #1 (a) : " +  s )
    puts( "In Fiber #1 (b) : " +  s )
    Fiber.yield
    puts( "In Fiber #1 (c) : " +  s )
}

f2 = Fiber.new {
    | s |
    puts( "In Fiber #2 (a) : " +  s )
    puts( "In Fiber #2 (b) : " +  s )
    Fiber.yield
    puts( "In Fiber #2 (c) : " +  s )
}

f.resume( "hello"  )
f2.resume( "hi" )
puts( "world" )
f2.resume
f.resume

This starts the first fiber, f, which runs until the call to yield. Then it starts the second fiber, f2, which runs until it too calls yield. Then the main program displays the string “world,” and finally f2 and f are resumed. This is the output:

In Fiber #1 (a) : hello
In Fiber #1 (b) : hello
In Fiber #2 (a) : hi
In Fiber #2 (b) : hi
world
In Fiber #2 (c) : hi
In Fiber #1 (c) : hello
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.144.37.12