Concurrency in Ruby

Topalov Alex @sharkzp 2014

Concurrency types

  • Threads(Java). Threads sharedin memory. Live long
  • New process per request(PHP). No Deadlocks and threadsafe. Die fast
  • Actor Model(Erlang, Scala). Messaging between actors

Global Interpreter Lock

GIL is a locking mechanism that is meant to protect your data integrity(CRuby, CPython) It force to run only one thread at a time even on a multicore processor

Why?

  • Some C extensation aren't Threadsafe
  • Deadlocks
  • Data integrity

Example

$ ruby pushing_nil.rb
5000

$ jruby pushing_nil.rb
4446

$ rbx pushing_nil.rb
3088
array = []

5.times.map do
  Thread.new do
    1000.times do
      array << nil
    end
  end
end.each(&:join)

puts array.size

Implementation

VALUE
rb_ary_push(VALUE ary, VALUE item)
{
    long idx = RARRAY_LEN(ary);

    ary_ensure_room_for_push(ary, 1);
    RARRAY_ASET(ary, idx, item);
    ARY_SET_LEN(ary, idx + 1);
    return ary;
}

Is it so bad?

 In web each thread spend quite a lot of time in IOs which won’t block the thread scheduler. So if you receive two quasi-concurrent requests you might not even be affected by the GIL

Yehuda Katz

Multiple Process/Froking

  • Passanger
  • Unicorn
  • Resque

It allow to fork as many process as need and control them in case of hanging or memory leaks

Actors/Fibers

  • Actors implementations like Celluloid(sidekiq)
  • Fibers

Non blocking IO/ Reactor pattern

  • Goliath
  • Thin
  • Twisted
  • EvenMachine
  • Node.js(http://howtonode.org/control-flow-part-ii/file-write.js)

Reactor Pattern

If DB query(I/O) blocking other requests then wrap it in a fiber, trigger an async call and pause the fiber so another request can get processed. Once the DB query comes back, it wakes up the fiber it was trigger from, which then sends the response back to the client. 

The Dining Philosophers Problem

Lets write some code! Finally! 

Credits:

Made with Slides.com