Skip navigation

For those of you who have played around with some bleeding edge asynchronous HTTP servers like python’s tornado and Ruby’s goliath, I am sure there have been several ahaaaa! moments finding out  things that need improvement. As part of these things, I find that structuring evented code and taking a bottom up approach to debugging nested calls can really dissuade you from asynchronous http approaches itself.

For the sake of convenience, I have taken a small block of code that you can write with eventmachine (Ruby’s most popular gem for building evented apps).

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

def asynchronous_call
  current_fiber = Fiber.current
  puts "making calls"
  http = EventMachine::HttpRequest.new("http://www.google.com").get :timeout => 10

  puts "declaring callbacks"

  http.callback {
    puts "resuming things";
    current_fiber.resume(http);
  }

  http.errback {
    puts "resuming things";
    current_fiber.resume(http);
  }

end

EventMachine.run do
  asynchronous_call
  puts "its all over"
end

##making calls
##declaring callbacks
##its all over
##resuming things

Its easy to see how cumbersome it gets to  debug evented code apart from the fact that it may get less cohesive progressively. Taking a bottom-up approach to debug nested calls is painful. Obviously it is possible to thread your way out of the situation and get things in order. However, that would tend to contribute to making the code less cohesive as well.

Fibers are a construct in ruby that are not essentially a concurrency construct but can effectively solve some of the same problems that threads intend to. Fibers are really nothing but coroutines that can simply be entered at several points and exitted at several points as well. In fact, a subroutine is a specific strain of a coroutine where there is only a single entry and exit point.


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

def asynchronous_call
  current_fiber = Fiber.current
  puts "making calls"
  http = EventMachine::HttpRequest.new("http://www.google.com").get :timeout => 10

  puts "declaring callbacks"

  http.callback {
    puts "resuming things";
    current_fiber.resume(http);
  }

  http.errback {
    puts "resuming things";
    current_fiber.resume(http);
  }

  puts "pausing fiber until call is complete"
  Fiber.yield
end

EventMachine.run do
  Fiber.new do
    asynchronous_call
    puts "its all over"
  end.resume
end

##making calls
##declaring callbacks
##pausing fiber until call is complete
##resuming things
##its all over

Obviously a cleaner way to structure and write evented code. Not only do co routines help you clearly bind the order of execution of code to the order that is apparent, but they are quite efficient in memory as well.

Unlike threads, Fibers are blessed with a memory stack of 20KB each. Every time a coroutine/Fiber is paused and restarted, the overhead of switching context is avoided since the memory stack is .. well already available.

Clearly this comes at the limitation of not having 100s of Fibers concurrently paused. It will simply blow your stack. However, with the above example the cohesiveness they bring into the code is commendable.

Its important to bear in mind that Fiber i not really a concurrency construct. Threads are. Clearly understanding the differences and similarities will help writing better evented code.

If you wish to understand more about Fibers in Ruby, here are a list of must read articles.

About these ads

One Trackback/Pingback

  1. By Networking - Page 4 on 06 May 2012 at 8:41 pm

    […] is constrained to underutilization of CPU. i want cohesive scalable and simple code. for example: http://blog.ashwinraghav.com/2011/05…t-driven-code/ https://github.com/igrigorik/em-synchrony https://github.com/davidbalbert/eventless it isn't a […]

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: