Hacker News new | past | comments | ask | show | jobs | submit login

There's a wide gulf between Ruby concurrency and Haskell concurrency.



There's a rather wide gulf between a moderate claim that there's a wide gulf between Ruby and Haskell concurrency, and the claim I responded to that it "isn't even something you can do with Ruby".

I am curious, though, what Haskell provides that can't be done with any of the current Ruby implementations? (not least because I'm back to working on my ahead of time/static Ruby compiler)


Generally parallelism is really much easier to express in a pure language and thus "sparked" parallelism is almost trivial to use in Haskell. I'm not sure that MRI even allows for parallel processes in its green threads due to GIL? Other Ruby implementations might have different restrictions there.

Also, as Edward mentions in his post on reddit, speculative parallelism is a Haskell one-liner.

    spec guess proc actual = 
      let speculation = proc guess 
      in s `par` if guess == actual 
                 then speculation 
                 else proc actual
(written in 5 lines for extra clarity on the syntax)


> I'm not sure that MRI even allows for parallel processes in its green threads due to GIL?

The GIL has no relevance when talking about processes. The GIL affects simultaneous execution of threads on multiple processor cores. It also does not prevent concurrency for threads or fibers. What it does prevent is for two system/kernel threads to be executing the Ruby interpreter code itself on different processors or cores at the same time.

This is generally not all that big of an issue, as e.g. any C extensions that are thread safe can tell the VM to yield from the thread that calls it, and any Ruby thread that does IO etc. will also be put back in the waiting queue and so won't hold the GIL.

> Other Ruby implementations might have different restrictions there.

jRuby, Rubinius and MacRuby are all GIL-less as far as I remember.

> Also, as Edward mentions in his post on reddit, speculative parallelism is a Haskell one-liner.

It's a little bit wordier in Ruby, but not much. There may better ways of doing it, but this spawns the "guess" thread (g), then spawns an "actual" thread (a), that if it finishes first will kill the guess thread (otherwise the guess thread will already have terminated, and the "kill" will do nothing. The main thread then waits for the g thread to terminate, either with a result or because it was killed. We then just try to kill "a" because we know either g terminated first, or a terminated it after it had finished - either way a is not needed any more. We then return whichever thread local variable has content.

    def spec guess, actual
      g = Thread.new { Thread.current[:ret] = guess.call }
      a = Thread.new { Thread.current[:ret] = actual.call; g.kill }
      g.join; a.kill
      g[:ret] || a[:ret]
   end
This requires "guess" and "actual" to be any object with a call method, which includes Proc/blocks/"lambda" statements (or "->" in Ruby 1.9). E.g:

   puts spec(-> { sleep(3); return "GUESS" }, -> { sleep(1); return "ACTUAL" })
In MRI 1.8 this will only execute on a single core. In 1.9+ it can use multiple cores, but will be subject to the GIL. On Rubinius and jRuby etc. it won't have to deal with a GIL. A multi process version would be immune to both. There are additional caveats to think about, like signals.

Of course this requires "guess" and "actual" to be thread safe.


Yeah, you're getting there at the end when you have no GIL and multiple cores being utilized. Without that, your speculative parallelism isn't faster, it's just as long unless it just happens to be threadsafe C extension IO.

Which is exactly the point. Haskell performs better with fewer caveats all the time.


No, it is substantially faster with the GIL too, for almost all "real" Ruby code. There are exceptions: code that spends most of their time in the interpreter. That's pretty much no Ruby code. If you're doing numeric computation etc. with present Ruby implementations, that would be impacted by it, you're doing something wrong - the method call overhead in all current Ruby implementations is too high for that to be a good idea.

And as I pointed out, the GIL is an issue in only one of at least 4 available Ruby implementations as of last count. So you're discounting the implementation based on the one Ruby implementation that is potentially scaling worse. Great. Let's find an old slow Haskell implementation to compare to too.

> Without that, your speculative parallelism isn't faster, it's just as long unless it just happens to be threadsafe C extension IO

Performance wasn't what was being discussed. The claim I responded to originally was that concurrency isn't "even something you can do with Ruby". I've demonstrated why that claim is flat out wrong, for every version of Ruby.

You then claimed "Generally parallelism is really much easier to express in a pure language and thus "sparked" parallelism is almost trivial to use in Haskell. I'm not sure that MRI even allows for parallel processes in its green threads due to GIL? Other Ruby implementations might have different restrictions there."

And I demonstrated how easy implementing speculative execution is in Ruby too, and pointed out that Ruby allows parallelism just fine even in old MRI version with green threads, new MRI versions with system threads, processes, or any of the number of non-MRI Ruby implementations that don't use a GIL, but with different tradeoffs.

You can continue to shift the goalposts if you like, but I've addressed the original claims sufficiently. And bringing up performance is irrelevant - I've pointed out the performance limitations myself repeatedly.

(and to whomever downvoted my reply above: that's the kind of childish reaction I'd have expected at Reddit, not here)




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: