Ruby Fibers for Cooperative I/O: A Practical Task Guide
A task guide to using Ruby Fibers for cooperative multitasking. Set up a minimal scheduler, write yielding fibers, integrate Ruby 3.x scheduler hooks, and verify behavior with checks and recovery options.
31 Aug 2026, 07:00 UTC

Desired outcome
Use Ruby Fibers for cooperative multitasking to keep an I/O-bound task responsive without OS threads. You will create a minimal scheduler, write fibers that yield at explicit points, and verify Fiber scheduler integration in Ruby 3.x.
Prerequisites
- Ruby 3.1 or newer with Fiber scheduler hooks available.
- Basic knowledge of Ruby blocks and the Fiber API.
- A terminal with ruby executable and permission to run scripts.
- Optional async gem for real-world scheduler integration.
Focused procedure
Create a minimal cooperative scheduler
A scheduler tracks ready fibers and resumes them in round-robin order.
class SimpleScheduler def initialize @ready = [] end def add(fiber) @ready << fiber end def run until @ready.empty? fiber = @ready.shift fiber.resume @ready << fiber if fiber.alive? end end endWrite a fiber that yields cooperatively
Fibers must yield explicitly. The example processes items and yields between items to allow other fibers to run.
scheduler = SimpleScheduler.new worker = Fiber.new do 3.times do |i| puts "worker step #{i}" Fiber.yield end end ticker = Fiber.new do 3.times do |i| puts "ticker #{i}" Fiber.yield end end scheduler.add(worker) scheduler.add(ticker) scheduler.runRun with ruby script.rb. The scheduler alternates between worker and ticker because each fiber yields.
Integrate with Ruby 3.x Fiber scheduler hooks
Ruby 3.x exposes Fiber.scheduler. Async libraries install a scheduler that yields on I/O readiness.
require 'async' Async do puts Fiber.scheduler.inspect # Inside Async block, Fiber.current is a fiber managed by Async::Scheduler endCheck Fiber.scheduler is set when the block runs. This shows the hook is active.
Verify fiber behavior
Run unit tests that create fibers, yield, and resume with values. Inspect Fiber.current inside the fiber block and Fiber.alive? after completion.
f = Fiber.new { Fiber.current.object_id } id = f.resume puts "fiber id returned: #{id}"
Expected checks and recovery options
- Check Fiber.current is not nil inside the fiber block.
- Check Fiber.alive? returns false after the fiber finishes.
- Check Fiber.scheduler is set when using an async library.
Limitations: Fibers are cooperative. A fiber that never yields stalls the scheduler. Blocking calls inside a fiber defeat the benefit and may stall the scheduler. Fibers share the same OS thread, so they do not provide parallelism for CPU-bound work.
Recovery options: Avoid blocking calls like sleep or synchronous IO inside fibers. Protect shared mutable data with Mutex when mixing fibers and threads. Keep call stacks shallow to avoid unintended re-entrancy and deep recursion.
Practical verification
Run the scheduler script and confirm fibers resume in order. Inspect Fiber.scheduler with and without Async. If a fiber appears stuck, add explicit Fiber.yield points or replace blocking operations with non-blocking alternatives.