Bird
Raised Fist0
Rubyprogramming~15 mins

Fiber for cooperative concurrency in Ruby - Deep Dive

Choose your learning style10 modes available
Overview - Fiber for cooperative concurrency
What is it?
A Fiber in Ruby is a special kind of lightweight thread that allows a program to pause and resume execution at specific points. Unlike regular threads, Fibers do not run in parallel but cooperate by yielding control back and forth. This lets you write code that can manage multiple tasks without the complexity of full threading.
Why it matters
Fibers exist to help programs handle multiple tasks smoothly without the overhead and complexity of real threads. Without Fibers, managing tasks like waiting for input or processing data in chunks would require complicated code or slow down the program. Fibers make it easier to write efficient, readable code that handles many things seemingly at once.
Where it fits
Before learning Fibers, you should understand basic Ruby programming, methods, and blocks. Knowing about threads and how concurrency works in general helps. After Fibers, you can explore more advanced concurrency tools like Threads, Async gems, or EventMachine for real parallelism or event-driven programming.
Mental Model
Core Idea
Fibers let your program pause and resume tasks cooperatively, handing control back and forth like passing a baton in a relay race.
Think of it like...
Imagine two friends playing catch with a ball. One throws the ball (runs some code), then waits for the other to catch it and throw it back (yield control). They take turns throwing and catching, cooperating to keep the game going smoothly without rushing or interrupting each other.
┌─────────────┐       ┌─────────────┐
│ Fiber A     │       │ Fiber B     │
│ Running     │       │ Paused      │
│ (has ball)  │──────▶│ (waiting)   │
│             │       │             │
│  yield      │       │ resume      │
└─────────────┘       └─────────────┘
       ▲                     │
       │                     ▼
┌─────────────┐       ┌─────────────┐
│ Fiber B     │       │ Fiber A     │
│ Running     │       │ Paused      │
│ (has ball)  │──────▶│ (waiting)   │
│             │       │             │
│  yield      │       │ resume      │
└─────────────┘       └─────────────┘
Build-Up - 7 Steps
1
FoundationUnderstanding basic Ruby methods
🤔
Concept: Learn how Ruby methods work and how code executes step-by-step.
Ruby methods are blocks of code you can call by name. When you call a method, Ruby runs its code from top to bottom, then returns a result. This linear flow is the foundation before adding pauses or switching tasks.
Result
You can write and call simple methods that run completely before moving on.
Knowing how Ruby runs code normally helps you see how Fibers change this flow by pausing and resuming.
2
FoundationIntroduction to Ruby blocks and yield
🤔
Concept: Blocks let you pass chunks of code to methods, and yield lets methods run those blocks.
In Ruby, you can pass a block to a method and call it inside with yield. This lets methods run extra code you provide, making your programs more flexible.
Result
You can write methods that run other code inside them, controlling when and how it runs.
Understanding yield is key because Fibers use a similar idea to pause and resume execution.
3
IntermediateCreating and running a Fiber
🤔Before reading on: do you think a Fiber runs immediately when created or only when resumed? Commit to your answer.
Concept: Fibers are created with a block but only start running when you call resume on them.
You create a Fiber by giving it a block of code. This code doesn't run right away. Instead, you call resume to start or continue the Fiber. Inside the Fiber, you can call Fiber.yield to pause and return control.
Result
The Fiber runs until it hits yield, then pauses. Calling resume again continues from where it left off.
Knowing that Fibers start paused and run only when resumed helps you control task switching explicitly.
4
IntermediateSwitching control between Fibers
🤔Before reading on: do you think Fibers switch automatically or only when you tell them to? Commit to your answer.
Concept: Fibers switch control only when you explicitly call resume or yield, making concurrency cooperative.
Fibers do not run in parallel. Instead, they cooperate by yielding control back to the caller or another Fiber. You decide exactly when to switch, so the program stays predictable and easy to follow.
Result
You can write code that switches between tasks smoothly without race conditions or surprises.
Understanding cooperative switching prevents confusion about Fibers running at the same time like threads.
5
IntermediatePassing data between Fiber and caller
🤔Before reading on: do you think Fibers can send and receive data when switching? Commit to your answer.
Concept: Fibers can exchange values with the code that resumes or yields them, enabling communication between tasks.
When you call resume, you can pass a value into the Fiber. When the Fiber yields, it can send a value back. This two-way data flow lets Fibers work together and share information.
Result
Fibers become more powerful by not just pausing but also exchanging data with the rest of the program.
Knowing Fibers communicate data helps you design cooperative tasks that depend on each other.
6
AdvancedUsing Fibers for cooperative concurrency
🤔Before reading on: do you think Fibers can replace threads for all concurrency needs? Commit to your answer.
Concept: Fibers let you manage multiple tasks by switching between them manually, useful for IO or event-driven programs without real parallelism.
By creating multiple Fibers and resuming them in turn, you can simulate multitasking. This is great for programs that wait on input or network calls, letting other tasks run while waiting.
Result
Your program feels responsive and efficient without the complexity of threads or locks.
Understanding Fibers as a tool for cooperative multitasking clarifies when and why to use them instead of threads.
7
ExpertInternal Fiber state and stack switching
🤔Before reading on: do you think Fibers share the same call stack or have separate stacks? Commit to your answer.
Concept: Fibers have their own call stack and execution context, allowing them to pause and resume independently within the same thread.
Under the hood, Ruby Fibers save their current position and local variables on their own stack. When resumed, the Fiber restores this state and continues. This lightweight stack switching is faster than full threads but limited to cooperative control.
Result
Fibers provide efficient context switching without OS thread overhead but require explicit yielding.
Knowing Fibers have separate stacks explains why they can pause and resume without losing state, unlike simple method calls.
Under the Hood
Ruby Fibers work by saving the current execution context, including the call stack and local variables, when Fiber.yield is called. This context is stored separately from the main thread's stack. When Fiber.resume is called, Ruby restores this saved context and continues execution from the paused point. This switching happens entirely in user space without kernel involvement, making it very fast but cooperative.
Why designed this way?
Fibers were designed to provide lightweight concurrency without the complexity and overhead of OS threads. By requiring explicit yielding, Fibers avoid race conditions and locking issues common in preemptive threading. This design fits Ruby's focus on simplicity and developer control, allowing efficient multitasking especially for IO-bound tasks.
Main Thread
┌───────────────────────────────┐
│                               │
│  Calls Fiber.resume           │
│       │                       │
│       ▼                       │
│  ┌───────────────┐            │
│  │ Fiber Stack   │            │
│  │ (saved state) │◀───────────┤
│  └───────────────┘            │
│       ▲                       │
│       │                       │
│  Fiber.yield saves state      │
│  and returns control          │
└───────────────────────────────┘
Myth Busters - 4 Common Misconceptions
Quick: Do Fibers run in parallel like threads? Commit to yes or no.
Common Belief:Fibers are just like threads and run code at the same time in parallel.
Tap to reveal reality
Reality:Fibers do not run in parallel; they run cooperatively by explicitly yielding control back and forth.
Why it matters:Believing Fibers run in parallel can lead to expecting thread-like behavior, causing bugs when Fibers don't switch automatically.
Quick: Can Fibers be preempted by the system without your code's help? Commit to yes or no.
Common Belief:Fibers can be interrupted and switched by the system anytime, like threads.
Tap to reveal reality
Reality:Fibers only switch when your code calls yield or resume; the system does not preempt them.
Why it matters:Expecting preemption can cause missed task switches and unresponsive programs if yield is not used properly.
Quick: Do Fibers share the same call stack? Commit to yes or no.
Common Belief:All Fibers share the same call stack as the main thread.
Tap to reveal reality
Reality:Each Fiber has its own call stack and local variables, allowing independent execution states.
Why it matters:Misunderstanding this can cause confusion about variable scope and why Fibers can pause and resume without losing data.
Quick: Can Fibers be used for CPU-bound parallel processing? Commit to yes or no.
Common Belief:Fibers can speed up CPU-heavy tasks by running them in parallel.
Tap to reveal reality
Reality:Fibers do not run in parallel and cannot speed up CPU-bound tasks; they are best for IO-bound or cooperative multitasking.
Why it matters:Using Fibers for CPU-heavy work wastes time and resources, leading to poor performance.
Expert Zone
1
Fibers can be nested, meaning a Fiber can resume another Fiber, creating complex cooperative flows that require careful management.
2
Exception handling inside Fibers behaves differently; exceptions propagate to the caller of resume, which can affect error management strategies.
3
Fibers interact subtly with Ruby's garbage collector; keeping references to Fibers alive affects memory and lifecycle, which experts must monitor.
When NOT to use
Fibers are not suitable when true parallelism is needed, such as CPU-bound tasks or multi-core processing. In those cases, use Ruby Threads or external processes. Also, Fibers require explicit yielding, so they are not ideal for libraries or code that cannot control execution flow.
Production Patterns
In production, Fibers are often used in event-driven servers, like web servers or network clients, to handle many connections efficiently without blocking. Frameworks like Async or libraries like EventMachine build on Fibers to provide cooperative concurrency with readable code.
Connections
Coroutines in other languages
Fibers are Ruby's version of coroutines, which exist in languages like Python and Lua.
Understanding Fibers helps grasp coroutines elsewhere, revealing a common pattern of cooperative multitasking across programming languages.
Operating system threads
Fibers differ from OS threads by being cooperative and lightweight, while threads are preemptive and managed by the OS.
Knowing this contrast clarifies when to choose Fibers for simplicity and efficiency versus threads for true parallelism.
Human multitasking and attention switching
Fibers mimic how humans switch attention between tasks deliberately rather than automatically.
This connection shows how cooperative concurrency models real-world task management, helping understand why explicit yielding is needed.
Common Pitfalls
#1Forgetting to call Fiber.yield inside a Fiber, causing it to run to completion without pausing.
Wrong approach:fiber = Fiber.new { puts 'Start'; puts 'End' } fiber.resume fiber.resume
Correct approach:fiber = Fiber.new { puts 'Start'; Fiber.yield; puts 'End' } fiber.resume fiber.resume
Root cause:Misunderstanding that Fibers only pause when Fiber.yield is called, so without it, the Fiber runs fully on first resume.
#2Trying to resume a Fiber that has already finished, causing an error.
Wrong approach:fiber = Fiber.new { puts 'Done' } fiber.resume fiber.resume # Error here
Correct approach:fiber = Fiber.new { puts 'Done' } fiber.resume # Do not resume again after completion
Root cause:Not tracking Fiber state leads to resuming a dead Fiber, which Ruby does not allow.
#3Expecting Fibers to run in parallel and not yielding control, causing unresponsive programs.
Wrong approach:fiber1 = Fiber.new { loop { puts 'A' } } fiber2 = Fiber.new { loop { puts 'B' } } fiber1.resume fiber2.resume
Correct approach:fiber1 = Fiber.new { loop { puts 'A'; Fiber.yield } } fiber2 = Fiber.new { loop { puts 'B'; Fiber.yield } } loop do fiber1.resume fiber2.resume end
Root cause:Expecting automatic switching without explicit yield causes one Fiber to block others.
Key Takeaways
Fibers provide a way to pause and resume code cooperatively within a single thread, enabling lightweight multitasking.
They differ from threads by requiring explicit yielding, which gives the programmer full control over task switching.
Each Fiber has its own call stack and execution context, allowing independent progress without losing state.
Fibers are best suited for IO-bound or event-driven programs, not for CPU-bound parallel processing.
Understanding Fibers helps write efficient, readable concurrent Ruby code without the complexity of full threading.

Practice

(1/5)
1. What is the main purpose of using Fiber in Ruby?
easy
A. To pause and resume tasks manually for cooperative multitasking
B. To create multiple threads that run in parallel automatically
C. To speed up code by running it on multiple CPU cores
D. To handle database connections asynchronously

Solution

  1. Step 1: Understand Fiber's role

    Fibers allow manual pausing and resuming of code execution, enabling cooperative multitasking.
  2. Step 2: Differentiate from threads

    Unlike threads, Fibers do not run in parallel automatically; they require explicit control.
  3. Final Answer:

    To pause and resume tasks manually for cooperative multitasking -> Option A
  4. Quick Check:

    Fiber = manual pause/resume [OK]
Hint: Fibers pause and resume tasks manually, not parallel threads [OK]
Common Mistakes:
  • Confusing Fibers with threads or parallelism
  • Thinking Fibers run automatically in background
  • Assuming Fibers speed up CPU usage
2. Which of the following is the correct way to create a Fiber in Ruby?
easy
A. fiber = Fiber.start { puts 'Hello' }
B. fiber = Fiber.new { puts 'Hello' }
C. fiber = Fiber.create { puts 'Hello' }
D. fiber = Fiber.run { puts 'Hello' }

Solution

  1. Step 1: Recall Fiber creation syntax

    Ruby uses Fiber.new with a block to create a new Fiber.
  2. Step 2: Check other options

    Methods like create, start, or run do not exist for Fiber creation.
  3. Final Answer:

    fiber = Fiber.new { puts 'Hello' } -> Option B
  4. Quick Check:

    Fiber creation = Fiber.new [OK]
Hint: Use Fiber.new with a block to create a Fiber [OK]
Common Mistakes:
  • Using non-existent Fiber methods like create or start
  • Forgetting to pass a block to Fiber.new
  • Confusing Fiber with Thread syntax
3. What will be the output of the following Ruby code?
fiber = Fiber.new do
  puts 'Step 1'
  Fiber.yield
  puts 'Step 2'
end

fiber.resume
puts 'Between'
fiber.resume
medium
A. Step 2 Between Step 1
B. Step 1 Step 2 Between
C. Between Step 1 Step 2
D. Step 1 Between Step 2

Solution

  1. Step 1: Trace first resume call

    Calling fiber.resume runs until Fiber.yield, printing 'Step 1'.
  2. Step 2: Trace code after first resume

    After yield, control returns to main, printing 'Between'.
  3. Step 3: Trace second resume call

    Second fiber.resume resumes after yield, printing 'Step 2'.
  4. Final Answer:

    Step 1 Between Step 2 -> Option D
  5. Quick Check:

    Fiber.yield pauses, resume continues [OK]
Hint: Fiber.yield pauses; resume continues after yield [OK]
Common Mistakes:
  • Assuming all code runs at first resume
  • Confusing order of prints around yield
  • Thinking yield stops Fiber permanently
4. Identify the error in this Fiber usage:
fiber = Fiber.new do
  puts 'Start'
  Fiber.yield
  puts 'End'
end

fiber.yield
fiber.resume
medium
A. Calling Fiber.yield outside a Fiber block causes an error
B. Fiber.resume must be called before Fiber.yield
C. Fiber.new requires a parameter for yield count
D. Fiber cannot print inside its block

Solution

  1. Step 1: Check where Fiber.yield is called

    The code calls fiber.yield outside the Fiber block, which is invalid.
  2. Step 2: Understand Fiber.yield usage

    Fiber.yield is a class method to pause current Fiber, not an instance method on Fiber objects.
  3. Final Answer:

    Calling Fiber.yield outside a Fiber block causes an error -> Option A
  4. Quick Check:

    Fiber.yield only inside Fiber block [OK]
Hint: Fiber.yield is called inside Fiber block only [OK]
Common Mistakes:
  • Calling fiber.yield instead of Fiber.yield
  • Expecting Fiber.resume before yield call
  • Thinking Fiber.new needs parameters for yield
5. Given two Fibers that alternate printing numbers, what is the output of this code?
fiber1 = Fiber.new do
  3.times do |i|
    puts "Fiber1: #{i}"
    Fiber.yield
  end
end

fiber2 = Fiber.new do
  3.times do |i|
    puts "Fiber2: #{i}"
    Fiber.yield
  end
end

while fiber1.alive? || fiber2.alive?
  fiber1.resume if fiber1.alive?
  fiber2.resume if fiber2.alive?
end
hard
A. Fiber2: 0 Fiber1: 0 Fiber2: 1 Fiber1: 1 Fiber2: 2 Fiber1: 2
B. Fiber1: 0 Fiber1: 1 Fiber1: 2 Fiber2: 0 Fiber2: 1 Fiber2: 2
C. Fiber1: 0 Fiber2: 0 Fiber1: 1 Fiber2: 1 Fiber1: 2 Fiber2: 2
D. Fiber1: 0 Fiber2: 0 Fiber2: 1 Fiber1: 1 Fiber1: 2 Fiber2: 2

Solution

  1. Step 1: Understand Fiber alternation

    Each Fiber prints a number then yields, pausing itself.
  2. Step 2: Trace the while loop

    The loop resumes fiber1 then fiber2 alternately while they are alive.
  3. Step 3: Follow output order

    Output alternates: Fiber1:0, Fiber2:0, Fiber1:1, Fiber2:1, Fiber1:2, Fiber2:2.
  4. Final Answer:

    Fiber1: 0 Fiber2: 0 Fiber1: 1 Fiber2: 1 Fiber1: 2 Fiber2: 2 -> Option C
  5. Quick Check:

    Fibers alternate resume and yield [OK]
Hint: Fibers alternate resume and yield to interleave output [OK]
Common Mistakes:
  • Assuming one Fiber runs completely before the other
  • Mixing order of Fiber resumes
  • Forgetting Fiber.yield pauses execution
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard