Is the GIL killing ruby?

The Web

This is all from the perspective of making web services. That’s all I know anything about.

Terminology

Every major ruby implementation allows concurrent operations using system threads. However, because of the GIL in MRI, many people say that ruby doesn’t have real threads. Even with the GIL, c code can ask for non-GIL’ed concurrency and things like IO, database adapters, etc already implement this. The GIL only kills concurrent ruby code and that is only on MRI.

Eco system

My question is why spend years implementing non-GIL threads in MRI?

My answer is “it doesn’t matter.”

This is why.

1. IO is good to go

IO and related operations are already concurrent, so a service dealing with mostly databases or external apis will benefit from threading in all major ruby implementations. I’ve written code dealing with copying files over the network, then verifying them and I could easily bombard remote drives with data using threads on MRI. Threads are not broken on MRI, they are just ultra conservative and “safe.”

2. jruby is amazing

How can the work on MRI ever be better than jruby with regards to threading support? Also, the existing java libs dealing with concurrency are so mature, it is a tall order to do better. I guarantee that if this work were done, people would immediately cry about how inferior it is to jruby. It’s already happening with work on MRI’s GC. That isn’t a good reason to not pursue it ever, but be realistic - how long would it take to add threads to MRI that are competitive with the jvm.

Not everyone has experience with java or the jvm and therefore might not want to try out jruby because of unfamiliarity with the tools. These people get the GIL. If the GIL ends up slowing them down, then they can invest in learning the jvm and it’s associated tools. Honestly, we should all do this anyway (talking to myself as well).

3. Don’t forget about rubinius and macruby

First, you may think it odd to mention macruby, but objective-c has amazing support for threads. Using GCD a programmer can saturate all the cores of a machine in a controlled way without even trying. I think macruby will see more use for small services that deal with things the cocoa apis already cover well, webkit related tasks, and because so many people are learning objective-c to make iOS apps and are getting comfortable with it.

I have not used rubinius on any production concurrent code, but people smarter than me have told me it works well and even has built in things like Actors to make the job easier.

4. php, python, and javascript

Don’t put your fingers in your ears and ignore how much of the internet runs on these languages. They at best have a GIL and at worst are compiled anew every request. Node is moving forward in popularity because it allows certain types of services to be developed faster and the deployment options are maturing, the largest site in the world runs on php, and django was made to create high traffic publishing sites. All of these do fine without the need to have fully unlocked system native threads.

5. Today’s web is built atop processes

Maybe in the future everyone will understand threading or libraries like Celluloid will make it more understandable and everyone will use threads for everything. But today, web scaling is done by running more processes on more machines. Unicorn is the perfect example of using unix processes to get work done in a web request scenario. Scaling with processes is understood.

If someone wants to deploy massively concurrent services, there is the maturity of the jvm. This cannot be stated enough. Jruby benefits from all the work already invested in the jvm and all the work we know will be invested in the future. It’s an amazing option and we all owe a great debt to its core team and contributors. Seriously, buy them a beer, coffee, cookie, or something if you ever run into them.

6. Go ahead and do it

If someone did work on implementing non-GIL threads for ruby, we all would be grateful to their work. There is nothing stopping someone from possibly using the work from rubinius or starting from scratch.

I know nothing about how to do this, but I do know that as long as ruby continues to be a joy to use, adding threads to MRI wouldn’t hurt anyone, it’s just not something that needs to be hurried in.

The future

Matz has said he is not a threading guy. He has called upon the community to investigate threading and report back what it finds.

So far it has determined that threads are awesome and the jvm works quite well. It has also found that scaling with processes is proven to work, admittedly at the expense of RAM. GC modifications can make that better, but it will always be a problem with the process approach.

This is great news. We have many good options to pick from based on our needs. MRI is great for those wanting to use c extensions, rubinius great for concurrency and modernity, and jruby is great for concurrency and speed.

Ruby is no less relevant or less useful because of the GIL. In fact, there has never been a better time to be writing web services in ruby.