rubyconcurrencyeventmachinefiber

How does one achieve parallel tasks with Ruby's Fibers?


I'm new to fibers and EventMachine, and have only recently found out about fibers when I was seeing if Ruby had any concurrency features, like go-lang.

There don't seem to be a whole lot of examples out there for real use cases for when you'd use a Fiber.

I did manage to find this: https://www.igvita.com/2009/05/13/fibers-cooperative-scheduling-in-ruby/ (back from 2009!!!)

which has the following code:

require 'eventmachine'
require 'em-http'
require 'fiber'

def async_fetch(url)
  f = Fiber.current
  http = EventMachine::HttpRequest.new(url).get :timeout => 10
  http.callback { f.resume(http) }
  http.errback { f.resume(http) }

  return Fiber.yield
end

EventMachine.run do
  Fiber.new{
    puts "Setting up HTTP request #1"
    data = async_fetch('http://www.google.com/')
    puts "Fetched page #1: #{data.response_header.status}"

    EventMachine.stop
  }.resume
end

And that's great, async GET request! yay!!! but... how do I actually use it asyncily? The example doesn't have anything beyond creating the containing Fiber.

From what I understand (and don't understand):

async_fetch is blocking until f.resume is called.

f is the current Fiber, which is the wrapping Fiber created in the EventMachine.run block.

the async_fetch yields control flow back to its caller? I'm not sure what this does

why does the wrapping fiber have resume at the end? are fibers paused by default?

Outside of the example, how do I use fibers to say, shoot off a bunch of requests triggered by keyboard commands?

like, for example: every time I type a letter, I make a request to google or something? - normally this requires a thread, which the main thread would tell the parallel thread to launch a thread for each request. :-\

I'm new to concurrency / Fibers. But they are so intriguing!

If anyone can answers these questions, that would be very appreciated!!!


Solution

  • There is a lot of confusion regarding fibers in Ruby. Fibers are not a tool with which to implement concurrency; they are merely a way of organizing code in a way that may more clearly represent what is going on.

    That the name 'fibers' is similar to 'threads' in my opinion contributes to the confusion.

    If you want true concurrency, that is, distributing the CPU load across all available CPU's, you have the following options:

    In MRI Ruby

    Running multiple Ruby VM's (i.e. OS processes), using fork, etc. Even with multiple threads in Ruby, the GIL (Global Interpreter Lock) prevents the use of more than 1 CPU by the Ruby runtime.

    In JRuby

    Unlike MRI Ruby, JRuby will use multiple CPU's when assigning threads, so you can get truly concurrent processing.

    If your code is spending most of its time waiting for external resources, then you may not have any need for this true concurrency. MRI threads or some kind of event handling loop will probably work fine for you.