views:

2302

answers:

4

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.

+3  A: 

The normal solution for MRI is to run multiple Rails instances, each handling requests independently. Since MRI isn't multithreaded anyway, you can't run multiple Rails instances on top of it. This means you take a memory hit since Rails is loaded once per Ruby process.

Since JRuby supports native threads, you could always run several Rails instances in a single JVM. But with Rails being thread-safe, you can cut it down to one, which means lower memory usage and less JIT compilation.

Charles Nutter (JRuby) has a nice summary.

Kjetil Ødegaard
Thanks, Charles Nutter's summary is great.
auramo
+1  A: 

I really suggest you to watch Jim Weirich`s speech from RubyConf 2008 (it's very funny and informative:) :

http://rubyconf2008.confreaks.com/what-all-rubyist-should-know-about-threads.html

This one is nice too:

http://rubyconf2008.confreaks.com/summer-of-code-rails-thread-safety.html

Marcin Urbanski
+1  A: 

I think the previous posters covered the Rails cases pretty well, so I won't bother going into that sort of stuff.

It's certainly possible to write threaded Ruby applications. Some of the problems that exist with ruby threads is that they are 'green' in as they are managed by the virtual machine. Currently, the default interpreter (MRI) only has one true system thread that need to be shared by all of the threads that the interpreter has control over.

The downside to this is that if you have a computer with multiple processors or cores you can't have a thread in your application running on some other core. This is a pretty big deal for people running servers and high performance apps.

As for your interpreter-specific-code question: I don't think so. AFAIK you don't have to do anything special to take care of JRuby/JVM threads.

Also: This article over on Igvita that takes a good look at the state of concurrency in Ruby.

CJ Bryan
+4  A: 

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.

Brian Guthrie