Marcos Castilho

Why rubyists ignore concurrency?

September 16, 2012

Concurrency (threaded concurrency in the context of this article) is a very interesting subject in the ruby community. On one hand, you have language implementators and gem writers going through a lot of hurdles to implement it correctly. On the other hand, you have the community at large doing its best effort to ignore the whole thing and still writing single threaded apps. Why?

It is a hard problem

Concurrency is a very hard thing to do. You can get yourself bitten by the slightest mistake and nasty bugs that are impossible to debug are a constant reality. But then, so is every other software problem you approach without conscious thought and good techniques.

The multicore overlords did not arrive

Functional programming zealots have been making prophecies about the end of OO programming due to our 'multicore' future for quite some time. They have a very valid point, it is getting ridiculous to ignore concurrency while even our smartphones have multiple cores, but the doomsayers didn't take into account the force of the cloud.

Instead of worrying about how to make the best use of the 10 cores of a server you can just boot 10 AWS instances. Who needs concurrency when you can just throw money at the problem?

The language itself does not care

Ruby 1.8 and 1.9 have the infamous GIL. If you don't know what that is please go read Matt Aimonetti's very good post about it. The GIL was a conscious decision of Matz and the early ruby developers to just ignore concurrency issues while they were building an awesome dynamic language.

They probably had very good reasons for that, and the lock is not as inefficient as people think, but still, it created the ruby culture of simply ignore thread safety and the whole threaded concurrency area.

While other languages are seeing great progress on writing safe and maintainable concurrent code, with things like Go routines and channels and Clojure's use of STM, the average ruby guy still does not know what a Mutex is all about.

You can live without it

Ok, we suck and don't use concurrency very well. But still, Ruby is being used to serve apps to a bazzilion users and generating tons of money, performing well under load. That's undeniable proof that you can ignore threads and live happily ever after.

After all, threaded concurrency is not the only way of scaling, you can spawn or fork processes, do asynchronous computations with background workers, use an evented reactor and lots of other options.

These options work very well, but they have a somewhat hidden cost of leaving ruby with a big memory footprint. You can always add more machines to the problem, but that doesn't change the fact that all of our apps could a have a very big efficient boost if only we cared about concurrency.

The Sidekiq gem is a very good example of that. It is a Resque 'clone', but built with threaded and concurrency issues in mind. The result is a gem that's getting very famous for saving people's money on AWS accounts.

Ignoring a problem does not solve anything

Yes, concurrency is hard. Yes, every single statement I made above is full of caveats. But, even so, concurrent code is not equal to bad code. There are a lot of good models that can help you write awesome concurrent code without tripping in mutexes on every second line of code.

Big companies can solve this problem with money, but can your awesome but still not known startup do the same? Why don't we just use computer science instead? Ignoring threads is not doing our community any favors. The next time you add yet another node to your web farm, stop and think if adding some concurrency would not solve your problem.

So please, go read something about threads, actors, or channels and bring that knowledge back into our community.