On Monday 28 July 2008 23:17:22 Kyle M. wrote:
With Matz supposedly making Ruby 2.0 right now, is it possible to make
it concurrent like Erlang
Not like Erlang, no.
Erlang does a couple of things differently. The most obvious one, which
it so scalable, is the message-passing – Erlang uses “processes” and
message-passing almost as a programming paradigm. We talk
about “Object-Oriented Programming”; Erlang people talk
about “Concurrency-Oriented Programming”.
These are much easier to write and scale than threads, and they perform
better than single threads.
There are a few of us working to rectify this situation, at least
semantically – there’s Revactor, Dramatis, and my own unreleased
which I’ve been wasting a few weekend hours on.
Another reason, which I’m running into while working on the above
that Erlang has no mutable data. It even goes so far as to make
single-assignment, which is just annoying, but the data structures
are never changed. Take a simple (contrived) Ruby example:
options[:foo] ||= ‘Foo’
options[:bar] ||= ‘Bar’
options[:foobar] ||= options[:foo] + options[:bar]
some_file.each_line do |line|
line.gsub! /curses/i, ‘******’
See, we’re changing things. Arrays, strings, whatever – it’s actually
characters inside the string that are changing.
In Erlang, (almost) no data ever changes, you just create new data.
means that when you send a message to another process, it’s as simple as
sending a pointer across – which means it’s not only a constant-time
operation, it’s an absurdly cheap constant-time operation. So the data
shared, but because it never changes, you don’t have to lock it.
Which means that in Erlang, message-passing is so cheap we don’t have to
about it. If we ported the message-passing to Ruby, it’s either
it’s massively expensive and still somewhat unreliable. I’m not sure
a good way around this, though if there is, I intend to find it.
so as to take advantage of the future
multi-core devices? Thank you.
This might happen – maybe, sort of. Keeping all of the above in mind,
threading in Ruby is modeled after the traditional C and Java model,
means they’re probably more expensive to create, and certainly more
dangerous, which means there won’t be as many of them.
On top of all that…
Right now, Ruby shares a problem with Python called the GIL – the
Giant) Interpreter Lock. What this means is that only one Ruby
may execute at a time. So even though they’re using separate OS threads,
even though different Ruby threads might run on different cores, the
your program (at least the Ruby part) is limited to the speed of a
The standard response, which you’ll probably already see (since I’m
time to write a longer answer), is that you can do threading in two
Either fork off a whole new Ruby process, so you probably can’t have any
shared-memory problems – and/or write the expensive parts in C, and
your C extension release the Ruby GIL.
(See, you can have more than one bit of C code running in a Ruby program
once, even alongside all the Ruby stuff – at least until they need to
something with Ruby itself.)
There’s also JRuby, which uses Java’s native threads, and has no GIL.
have been some problems with them lately, but they should work – but
keep all of the above in mind. You’ll be threading as well as Java does,
as well as Erlang does.
As you can probably tell, I’m not really happy about all of this.
Now, unlike Python, it looks as though the Ruby GIL might eventually be
removed. And there is JRuby. And there’s the various actor projects
included). So it’s conceivable that we’d get Ruby scalable to arbitrary
numbers of processors.
But again, I suspect Erlang is still going to do it better, if all you
about is multicore and efficiency. (Ruby is doing a better job of
has much more library support, and I much prefer its syntax.)