Class: Fiber
Overview
Fibers are primitives for implementing light weight cooperative concurrency in Ruby. Basically they are a means of creating code blocks that can be paused and resumed, much like threads. The main difference is that they are never preempted and that the scheduling must be done by the programmer and not the VM.
As opposed to other stackless light weight concurrency models, each fiber comes with a small 4KB stack. This enables the fiber to be paused from deeply nested function calls within the fiber block.
When a fiber is created it will not run automatically. Rather it must be be explicitly asked to run using the Fiber#resume
method. The code running inside the fiber can give up control by calling Fiber.yield
in which case it yields control back to caller (the caller of the Fiber#resume
).
Upon yielding or termination the Fiber returns the value of the last executed expression
For instance:
fiber = Fiber.new do
Fiber.yield 1
2
end
puts fiber.resume
puts fiber.resume
puts fiber.resume
produces
1
2
FiberError: dead fiber called
The Fiber#resume
method accepts an arbitrary number of parameters, if it is the first call to resume
then they will be passed as block arguments. Otherwise they will be the return value of the call to Fiber.yield
Example:
fiber = Fiber.new do |first|
second = Fiber.yield first + 2
end
puts fiber.resume 10
puts fiber.resume 14
puts fiber.resume 18
produces
12
14
FiberError: dead fiber called
Class Method Summary collapse
-
.current ⇒ Object
Returns the current fiber.
-
.yield(args, ...) ⇒ Object
Yields control back to the context that resumed the fiber, passing along any arguments that were passed to it.
Instance Method Summary collapse
-
#alive? ⇒ Boolean
Returns true if the fiber can still be resumed (or transferred to).
-
#initialize ⇒ Object
constructor
:nodoc:.
-
#resume(args, ...) ⇒ Object
Resumes the fiber from the point at which the last
Fiber.yield
was called, or starts running it if it is the first call toresume
. -
#transfer(args, ...) ⇒ Object
Transfer control to another fiber, resuming it from where it last stopped or starting it if it was not resumed before.
Constructor Details
#initialize ⇒ Object
:nodoc:
1083 1084 1085 1086 1087 |
# File 'cont.c', line 1083
static VALUE
rb_fiber_init(VALUE fibval)
{
return fiber_init(fibval, rb_block_proc());
}
|
Class Method Details
.current ⇒ Object
Returns the current fiber. You need to require 'fiber'
before using this method. If you are not running in the context of a fiber this method will return the root fiber.
1498 1499 1500 1501 1502 |
# File 'cont.c', line 1498
static VALUE
rb_fiber_s_current(VALUE klass)
{
return rb_fiber_current();
}
|
.yield(args, ...) ⇒ Object
Yields control back to the context that resumed the fiber, passing along any arguments that were passed to it. The fiber will resume processing at this point when resume
is called next. Any arguments passed to the next resume
will be the value that this Fiber.yield
expression evaluates to.
1484 1485 1486 1487 1488 |
# File 'cont.c', line 1484
static VALUE
rb_fiber_s_yield(int argc, VALUE *argv, VALUE klass)
{
return rb_fiber_yield(argc, argv);
}
|
Instance Method Details
#alive? ⇒ Boolean
Returns true if the fiber can still be resumed (or transferred to). After finishing execution of the fiber block this method will always return false. You need to require 'fiber'
before using this method.
1391 1392 1393 1394 1395 1396 1397 |
# File 'cont.c', line 1391
VALUE
rb_fiber_alive_p(VALUE fibval)
{
rb_fiber_t *fib;
GetFiberPtr(fibval, fib);
return fib->status != TERMINATED ? Qtrue : Qfalse;
}
|
#resume(args, ...) ⇒ Object
Resumes the fiber from the point at which the last Fiber.yield
was called, or starts running it if it is the first call to resume
. Arguments passed to resume will be the value of the Fiber.yield
expression or will be passed as block parameters to the fiber's block if this is the first resume
.
Alternatively, when resume is called it evaluates to the arguments passed to the next Fiber.yield
statement inside the fiber's block or to the block value if it runs to completion without any Fiber.yield
1414 1415 1416 1417 1418 |
# File 'cont.c', line 1414
static VALUE
rb_fiber_m_resume(int argc, VALUE *argv, VALUE fib)
{
return rb_fiber_resume(fib, argc, argv);
}
|
#transfer(args, ...) ⇒ Object
Transfer control to another fiber, resuming it from where it last stopped or starting it if it was not resumed before. The calling fiber will be suspended much like in a call to Fiber.yield
. You need to require 'fiber'
before using this method.
The fiber which receives the transfer call is treats it much like a resume call. Arguments passed to transfer are treated like those passed to resume.
You cannot resume a fiber that transferred control to another one. This will cause a double resume error. You need to transfer control back to this fiber before it can yield and resume.
Example:
fiber1 = Fiber.new do
puts "In Fiber 1"
Fiber.yield
end
fiber2 = Fiber.new do
puts "In Fiber 2"
fiber1.transfer
puts "Never see this message"
end
fiber3 = Fiber.new do
puts "In Fiber 3"
end
fiber2.resume
fiber3.resume
<em>produces</em>
In fiber 2
In fiber 1
In fiber 3
1465 1466 1467 1468 1469 1470 1471 1472 |
# File 'cont.c', line 1465
static VALUE
rb_fiber_m_transfer(int argc, VALUE *argv, VALUE fibval)
{
rb_fiber_t *fib;
GetFiberPtr(fibval, fib);
fib->transfered = 1;
return rb_fiber_transfer(fibval, argc, argv);
}
|