Ruby/Rails thread safety

auramo picture auramo · Mar 15, 2009 · Viewed 12.1k times · Source

I have been hacking with Ruby from time to time, but I haven't done anything big or multithreaded with it. I have heard that MRI only supports green threads and JRuby supports native threads via JVM. However, I stumble upon comments on blogs and discussion groups which say that "Rails is not thread-safe" or that Ruby itself is not thread safe. For example someone commented that there is a problem with the require statement. That sounds a bit fundamental.

I have seen a lot of Java apps which don't handle concurrency properly and I have nightmares about them from time to time :-) But at least you can write thread-safe applications in Java if you really know what you are doing (it's just not easy).

This all sounds quite alarming, can someone elaborate more - what is exactly the problem and how Rails manages to work at all if this is the case? Can I write multithreaded Ruby code which works correctly without race conditions and deadlocks? Is it portable between JRuby and MRI or do I have to hack in JVM specific code to take advantage of the JVM native threads properly?

EDIT:

I should have asked two questions, because people only seem to answer the rails threading stuff (which is nice in itself) and green threading vs. native threading. My concerns on core Ruby issues about thread safety haven't really been addressed. There seems to be at least an (unresolved?) issue with require in certain cases.

Answer

Brian Guthrie picture Brian Guthrie · Mar 16, 2009

First and foremost, Ruby 1.9 (the most recent official release) now uses native (kernel) threads. Previous versions of Ruby used green threads. To answer your question succinctly, prior to 1.9, threads have not commonly been used in Ruby applications large or small precisely because they're not particularly safe or reliable.

This is not particularly alarming because prior to version 2.2 Rails made no attempt to be threadsafe, and so we typically handle asynchronous processing through the use of multiple processes, database record locking, and message queues like Starling. This is generally a pretty reliable way to scale a web application--at least as reliable than incorrectly multithreaded Java applications--and has the added advantage that it becomes easier to scale your application sideways to multiple processors and servers.

I have no idea whether the 'require' issue you've mentioned has been resolved as of 1.9, but I do humbly venture that if you're requiring libraries dynamically in new threads then you have more than one maintainability problem.

If you'd like to avoid threads entirely, Ruby 1.9 also supports fibers, which employ a shared-nothing approach to concurrency and are, from what I gather, generally easier to write and maintain than threads. Performance numbers here.