Quantcast
Channel: Active questions tagged ruby - Stack Overflow
Viewing all articles
Browse latest Browse all 4616

Why are ruby fibers instantaneous when I set my silly scheduler?

$
0
0

I'm trying to understand (and accomplish) "interweaving" concurrency using ruby Fibers. To do that - I tried to implement my own scheduler but I hit a roadblock.

Here's the code to test:

f1 = Fiber.new do  puts "1: start"  sleep 2  puts "1: almost"   sleep 2  puts "1: done"end.resumef2 = Fiber.new do  puts "2: start"  sleep 2  puts "2: almost"   sleep 2  puts "2: done"end.resume

The theory is: without scheduler, the fibers are run sequentially, and the whole program takes 8s.If I manage to implement a scheduler that can pass on control to another thread on IO (sleep in this case), the fibers should wait together, and the whole program should take ~4s.

So, I partially implemented my silly scheduler:

class S  def initialize    @fibers = []      end  def block(blocker, timeout = nil)     fiber = Fiber.current    puts "block", blocker.inspect, timeout.inspect, fiber.inspect    @fibers << fiber  end  def unblock(blocker, fiber)     puts "unblock", blocker.inspect, fiber.inspect    @fibers.reject!{ _1 == fiber} # remove the fiber    fiber.resume  end  def fiber(&block)    Fiber.new(blocking: false, &block).tap(&:resume)  end  def kernel_sleep(duration = nil)     @fibers << Fiber.current  end  def io_wait(io, events, timeout)     puts "io_wait not implemented"  endend

I added this part before my test fibers:

Fiber.set_scheduler(S.new) if ENV['SCHEDULER'] == 'yes'

And the results completely surprised me: The fibers are not sleeping at all!

time SCHEDULER=yes ruby fiber-non-blocking-io.rb1: start1: almost1: done2: start2: almost2: doneSCHEDULER=yes ruby fiber-non-blocking-io.rb  0.05s user 0.03s system 99% cpu 0.083 total

What is going on here? I clearly don't understand how the scheduler is supposed to work.

My mental model was something like this (let's focus on kernel_sleep/sleep for simplicity):

  1. My fiber is resumed, outputs the first message, and hits sleep
  2. scheduler's kernel_sleep is called, and I store it for later2a. (I didn't get to implementing Fiber.yield to pass back the control)
  3. At some point, I should iterate over my sleeping fibers and check if it's time to resume them, but I didn't get to that part.

(The fact that the puts in the scheduler's code is not showing up also does not help. Clearly, the scheduler does something because the behavior changed, but I can't see those outputs)


Viewing all articles
Browse latest Browse all 4616

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>