Fibers and the scheduler

Fiber.new and resume

A fiber is a block with its own stack that runs until it yields and continues where it stopped. It is cooperative: nothing runs until the program calls resume:

ruby -e 'f = Fiber.new { Fiber.yield 1; 2 }; p f.resume, f.resume'

1 2

The first resume runs to the yield and returns 1; the second continues after it and returns 2. A third resume raises FiberError, because the block has finished.

Fiber.yield with a value

Both directions carry a value: resume(x) is the result of the Fiber.yield inside, and the value passed to yield is the result of the resume outside:

ruby -e 'f = Fiber.new { |x| y = Fiber.yield(x + 1); y * 2 }; p f.resume(1); p f.resume(5)'

2 10

That two-way hand-off is what an Enumerator uses internally and what a generator is built from. A fiber is not a thread: only one of them runs at a time, and the switch happens at an explicit yield.

The scheduler

Ruby 3 added a fiber scheduler: a class that the program registers, and the runtime calls it when a fiber blocks on I/O. The shape is three methods:

class Scheduler def fiber(&block) Fiber.new(blocking: false, &block) end def io_wait(io, events, timeout = nil) # wait for the socket, then return the events that are ready end def kernel_sleep(duration = nil) # suspend this fiber and resume it after the duration end end Fiber.set_scheduler(Scheduler.new)

With a scheduler installed, sleep and a socket read suspend the fiber instead of the thread, and one thread can hold thousands of waiting connections. The async gem is a scheduler with a production implementation; the standard library ships only the interface.

When a fiber helps

A fiber does not use a second core and does not make a CPU loop faster. For arithmetic, threads and processes are the previous lessons; a fiber is for code that waits.

What to watch for

A fiber that never yields blocks its thread exactly like a method. The scheduler only helps at the calls it knows: I/O and sleep. A long computation inside a fiber still stops everything.

Fibers in one thread share the same mutable state with no lock. A fiber switch can happen in the middle of an update, so the mutex rules from the thread lesson apply; the scheduler makes the bug less frequent, not impossible.

Next: Parallel work without a framework

Article author: Arthur Isaev