Steven Parkes : smparkes.net

Posts Tagged ‘threads’

Threadbare actors

9:31 AM
Palo Alto
2 July
2008

Interesting discussion about actors “with threads” and actors “without threads” here.

In the actor model, abstractly every actor has a thread. When not actually executing a method/responding to a message, i.e., most of the time, that abstract thread is blocked, waiting for a message.

These abstract threads may or may not be actually implemented with a real (read dedicated) thread. A thread will always be required to actually respond to a message/execute a method, but beyond that, there’s a bit more freedom in implementation.

The thread-per-actor approach generally raises issues of resources, and to a lesser extent, context switching. The weight of a thread varies from system to system, but with the exception of custom VMs, e.g., Erlang, threads are often resource intensive. Among other things, they need independent stacks.

On the other hand, in a thread-per-task (where a task represents a message sent to an actor/a method call on an actor), a pool of threads can be kept around and shared among actors as tasks are created. This makes the resource requirements for inactive actors much less.

All this makes it sound like task threads rather than actor threads are the way to go. However, there’s a gotcha: there’s a certain amount of state that needs to be maintained between messages. In actor systems with an explicit receive like Erlang, most if not all of the actor’s state is maintained on the stack. Since threads are usually how stack state is maintained, you generally need a dedicated thread.

Dramatis, however, is a bit more like Erlang/OTP gen_server than it is straight Erlang: the receive in dramatis is implicit, much as it is in Erlang/OTP’s gen_server. This has the side effect that there’s no stack state that needs to be maintained between receives. In these cases, in dramatis a thread isn’t dedicated to the actor. There are cases, however (rpc-like blocking calls, much like gen_server:call), where receipt of the response from the callee needs to continue where it left off in the caller: in those cases, dramatis does dedicate a thread, for the duration of that message exchange. Seems like a reasonable tradeoff, but it will depend a lot on the frequency of different styles of communication and at this point, we don’t have enough experience to know how that will fall out.

Seen lots of stuff on this lately, in Scala and in Kilim. Interesting times.

On a related subject, I setup a google group, actor-talk, that might be useful for this kind of “non-denominational” discussion about actors, that is, across language and library implementations. Seems to me it’s a small enough community at this point that it would be nice to learn from each others’ experiences, strengths, and weaknesses.

The many faces of threads

11:51 AM
Palo Alto
27 April
2008

Charlie Nutter gives a good roundup of Ruby implementations past to present, with a few guesses as to the future.

I’ve played with four: 1.8/MRI, 1.9/YARV, JRuby, and Rubinius. What I found a bit surprising is that I’ve come to appreciate pieces of all of them. MRI is pretty stable and widespread. 1.9 allows me to play with OS threads faster. JRuby allows me to play with the JVM crowd (and push threads even more). And I think we all owe the Rubinius for the spec work.

But there’s one thing that having four versions has helped immensely with: writing Ruby with threads. Threads can be such a bloody pain to develop. In all but the simplest programs, it gets pretty tough pretty quickly to be sure there are no unexpected sequences of events. When you run primarily on one platform/library, you pretty quickly surface the low hanging fruit: the races/sequences that occur most frequently on that platform. But there are all those rarer cases that kill you. Since they’re rare, they’re typically gone by the time you notice them and it’s virtually impossible to get them to repeat. So you start to rationalize: maybe I didn’t really see it; maybe I misinterpreted what I saw. Maybe it was a side effect of something else I already fixed.

But in the back of your mind, you wonder if you’re lying to yourself.

It’s the stuff of nightmares, a monster you just know is hiding under your bed.

In the case of Ruby, we have four implementations that share a pretty solid thread model … with wildly varying dynamics. In developing some threaded code, I started on MRI and made it solid. And then ran on 1.9 and everything went to hell because things were happening in a different order. Ditto for JRuby. So far, the only case where I didn’t surface more corner cases was Rubinius, which either means I’m getting farther out on the latent bug curve or I simply haven’t run enough tests on it.

If you’re writing threaded code on Ruby and it’s feasible, it might be worth considering developing on more than one VM, even if you only expect to actually roll one VM into production.

Of course, avoiding writing-down-and-dirty with threads is not the only nor (arguably) the best approach to concurrency, but you already knew that …