End of Life Ruby 3.0 has reached end of life and gets no more fixes. Switch to Ruby 4.0 →
Fiber
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 stack. This enables the fiber to be paused from deeply nested function calls within the fiber block. See the ruby(1) manpage to configure the size of the fiber stack(s).
When a fiber is created it will not run automatically. Rather it must 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 1_000_000 puts fiber.resume "The fiber will be dead before I can cause trouble"
produces
12 1000000 FiberError: dead fiber called
Non-blocking Fibers
Since Ruby 3.0, the concept of non-blocking fiber was introduced. Non-blocking fiber, when reaching any potentially blocking operation (like sleep, wait for another process, wait for I/O data to be ready), instead of just freezing itself and all execution in the thread, yields control to other fibers, and allows the scheduler to handle waiting and waking (resuming) the fiber when it can proceed.
For Fiber to behave as non-blocking, it should be created in Fiber.new with blocking: false (which is the default now), and Fiber.scheduler should be set with Fiber.set_scheduler. If Fiber.scheduler is not set in the current thread, blocking and non-blocking fiber’s behavior is identical.
Ruby doesn’t provide a scheduler class: it is expected to be implemented by the user and correspond to Fiber::SchedulerInterface.
There is also Fiber.schedule method, which is expected to immediately perform passed block in a non-blocking manner (but its actual implementation is up to the scheduler).
Class methods 7
Instance methods 9
Ruby version changes 7
-
3.0
-
Fiber.new(blocking: true/false) allows you to create non-blocking execution contexts. [Feature #16786] -
Fiber#blocking?tells whether the fiber is non-blocking. [Feature #16786] -
Fiber#backtraceandFiber#backtrace_locationsprovide per-fiber backtrace. [Feature #16815] -
The limitation of
Fiber#transferis relaxed. [Bug #17221] -
Introduce
Fiber.set_schedulerfor intercepting blocking operations andFiber.schedulerfor accessing the current scheduler. See fiber.md for more details about what operations are supported and how to implement the scheduler hooks. [Feature #16786] -
Fiber.blocking?tells whether the current execution context is blocking. [Feature #16786] -
Thread#joininvokes the scheduler hooksblock/unblockin a non-blocking execution context. [Feature #16786]
-