MacRuby Drops GIL, Gains Concurrent Threads
Threading in Ruby has always been a troublesome issue. Ruby 1.8 implements userspace threads with performance problems and also don't make use of multiple cores.
Ruby 1.9 switched to mapping every Ruby thread to a kernel thread, which removes some of the inefficiencies in 1.8's threads - yet still only one Ruby thread can run at a time.
The reason is the Global Interpreter Lock (GIL), sometimes referred to as Global VM Lock (GVL). Every Ruby thread needs to acquire the GIL before it can run. Ruby shares this implementation detail with languages like Python (where it's been a divisive issue for nearly a decade).
In the past few years, alternative Ruby implementations have done away with the issue: JRuby and IronRuby both don't have a GIL.
Now MacRuby joins their ranks and works without a GIL, as Laurent Sansonetti explains:
All MacRuby threads are scheduled by the OS kernel and registered into the Objective-C garbage collector (which runs on its own threads) before doing anything.
While the MacRuby runtime still has shared state across all threads, it now synchronizes the access to these structures instead of only allowing one thread to be active. The details:
The Core object contains a lock that is used every time a shared data structure is accessed. Shared data structures are for example: LLVM caches, various stubs caches, BridgeSupport caches, etc.
Everything else was moved to a VM class, which is completely lock-free. A VM object is created at demand and only once for every thread that wants to access the runtime. The VM object contains data structures for the very specific thread execution, like for instance current blocks, bindings, exceptions, etc. The VM sometimes calls the Core (when defining a method for example) which acquires the Core lock, but most of the time it just runs concurrently.
The new threading system is available in MacRuby's experimental branch, which is destined to become the next MacRuby version. The branch also contains a sample (and simple) web server built with MacRuby.
Once the next stable MacRuby version is released with the new threading code, there'll be three Ruby implementations with concurrent threads, without any GIL, vs. Ruby 1.8 (userspace threads) and Ruby 1.9.x. Both JRuby and MacRuby support the Ruby 1.9.x language and libraries.
Ruby 1.9.x shares the GIL problem with Python, albeit the Unladen Swallow project promises to remove the GIL by 2010 (whether that happens and whether the provided patches actually get merged into the official Python is another matter - patches that remove the GIL have been floating around for a decade).
A final note: discussions about GILs in either Ruby or Python often bring up the argument that threads in these languages simply aren't the proper way to get concurrency. Another argument is that the GIL is only a problem with CPU bound code - I/O bound code is not a problem since the GIL is properly released, allowing other threads to run during I/O operations. With that in mind - how do you implement CPU bound code that can make use of multiple cores in Ruby? Do you take care of creating and managing multiple OS processes?
Ruby Memory Model
Memory overhead of multi processing
Martin Thompson Jul 27, 2014