the blog for developers

Actor Myths

Actors are the new concurrency. They are everywhere. People make bold claims about actors, and while I do not agree with many of them, two in particular I regard as myths. Here they are:

  1. Actors are a shared nothing architecture
  2. Actors are easier to get right because of their shared nothing architecture

I know I’m alone with calling those myths, but here we go. Considering the first myth. If they share nothing, they could not collaborate on data. Sharing immutable messages does not help for getting data synced up again. So this can’t be the way to collaborate. Indeed actors do share everything! Each actor can be considered a data structure with state and a write lock (synchronized in Java).

The second myth. Actors are easier to get right because they share nothing and therefor do not have locks. As argued above they have locks, so this can’t be the reason why they are easier to get right. I consider two characteristics of actors to be the reason for them being easier:

  1. They only can hold one lock at a time (when using synchronized send messages). This is a common approach to prevent deadlocks in locking architectures.
  2. They mostly send asynchronous messages. This prevents the common problems that arise from holding locks and blocking. In locking architectures when accessing locks in an asynchronous way (e.g. with futures and timeouts) there are also no deadlocks for the calling thread.

I would like to learn something from this. So please keep your flaming minimal and help me understand possibles errors in my thinking instead.

Update: If you do not believe me concerning the shared-nothing part, read the example from James

You can leave a Reply here. Of course, you should follow me on twitter here.

You can share this post!
Do you want to tell others about this article? Use the social bookmark icons to submit this artice to the service of your choice. Thanks.

About the author: Stephan Schmidt has more than 15 years of internet technology experience and 10 years experience in agile. He was head of development, consultant and CTO and is a speaker, author and blog writer. He specializes in organizing and optimizing software development helping companies by increasing productivity with lean software development and agile methodologies. Want to know more? All views are only his own.

25 Tweets

Leave a reply.

Comments

Put differently: Actors are sharing other actors (with their state guarded by a lock which is defined by the sequential processing of the inbox).

Hey Stephan,

I think you have two bugs in your reasoning.

First, even if actors actually have state, they don’t make it leak to the outside: they just sit there waiting for messages, I don’t see how you see this as a sharing mechanism.

Second, actors don’t need locks on their own state, because it’s accessed by one and only one thread: don’t take the JVM as a reference, where locks are needed for ensuring memory visibility. Also, the correct way to interpret the statement “actors have no locks” is: actors have no contended or composed locks, that is, they don’t have liveness problems.

Let me know if I misunderstood your reasoning ;)

Cheers!

Sergio B.

@Sergio: My synchronized TicketManager does use the number of tickets has inc() and dec() methods and a R/W lock. It does not leak state either.

Several actors share the state of the TicketActor by holding references to the TicketActor and synchronizing via the mailbox of the TicketActor.

Second: The accessing by only one thread and a sequential mailbox is essentially a lock – you do not need to have a lock class to have a lock. Perhaps I should have better used the word semaphore.

First, why do you say several actors share the state of the TicketActor?
They may hold a reference to its address/pid/whatever, but they don’t see its state: the reference is used only for sending messages.

Second, I’ve got your point but again, you have to switch your point of view from “no locks/semaphores” to “no liveness problems”: does it clarify?

@Sergio: It does not matter if they see the state or not.

Pseudo Syntax:

class C1 {
TicketManager m = ...
}

class C2 {
TicketManager m = ...
}

class TicketManager {
private int tickets = 10;

def synchronized dec() {
if (tickets > 0) tickets--;
}
}

Neither C1 or C2 see the “state” in TicketManager. But obviously they share indirectly the tickets state.

Second: Well this was my explaination why actors do not have liveness and deadlock problems, but it’s not because they have no semaphores an not because they do not share state.

Considering

“Second, actors don’t need locks on their own state, because it’s accessed by one and only one thread: [...]”

Sometimes people say an actor has a thread (lightweight), but I think it’s better to think of the mailbox being a queue with one worker thread, the actor.

I can remember us sort of having the same discussion on twitter (@rvdarend is the handle). :)

You are talking about sharing state. If your definition of sharing is: “they have a way of viewing and changing the same data” – I agree.

The key point here is that it’s the actor that contains the state that is synchronizing these reads and writes.

So, yes, you can simulate actors bij having threads and locks and different actors can ’share state’ by messaging to the same third actor. The important difference is, however, that they cannot cause two threads to run through the same actor, at the same time.

All of this means that actors could be in completely different processes, on different hardware even. Now that’s a difference with threads running through the same, synchronous model.

And actually, all of this doesn’t mean actors have unique possibilities, far from it. It actually means you do not use a certain possiblity: multiple threads (on the same state/objects).

For this to work, one needs another way of having concurrency, that is where partitioning your model in smaller components comes in. I therefore think ‘Actors’ should contain ‘Aggregates’. I’ll be blogging/presenting about this soon.

@Rick: “The important difference is, however, that they cannot cause two threads to run through the same actor, at the same time.”

Yes, because the actor acts as a semaphore (wlock).

Waiting for your post :-)

@Rick: And with blocking sync send it essentially does not matter if the other actor is running in another thread.

And the problem goes away when using async send, which I wrote in the post.

You are certainly not alone. E.g. here is a (somewhat) related piece I wrote in January: http://code-o-matic.blogspot.com/2010/01/thoughts-on-actors.html

It’s not the new concurrency. It’s a slightly higher level programming interface, a bit cleaner than MPI, and it’s important to note that all the usual concurrency problems are *still here with us* (deadlocks, races, etc, all can be easily simulated). Seeing some slides of a JavaOne conference, titled, “Concurrency – You are doing it wrong” (basically claiming that using java.util.concurrent is wrong, we should be using actors instead, that’s the “true way” now!), I was quite annoyed with the sheer audaciousness of it.

I currently prefer lower level tools, more control, more easy to reason about performance, and so on. Actors are also good, I might use them more when the hype has died down.

@Dimitris: Thanks for the link.

” I was quite annoyed with the sheer audaciousness of it.”

I often feel the same.

@Stephan if you say that using the ‘Actor Model’ is basically the same as: ‘Don’t use multiple threads on the same data’ – on a technical level, I would agree with you.

Conceptually, it’s going back to the roots of OO, where Objects are fully encapsulated and can only message to each other (the way Alan Kay meant it to be).

Concluding, (and @Dimitris) so the hype is a bit undeserved, it’s mostly doing away with threads. Of course one should embrace it fully and only use one-way, asynchronous messaging (preferably eventing). So no request-response look-a-likes. This way, locking, race conditions and the like will not be a problem any more. Does this pose a formidable design challenge? Yes it does.

@Rick: I think it’s better to say: using the actor model is the same as: Use a queue with multiple producers and a single worker.

@stephan well, that would be the description of only one actor.

The real work is not in the implementation of one actor, but in partitioning your model in such a way that these actors really represent asynchronous parts/components/aggregates in your domain model.

I agree with Rick (above comment). Challenge (or rather use of Actors) is based on how you partition your model. In a system with 100s of producers and 100s of consumers use of actor model is useful based on how you partition it. And once you partition it, it becomes shared-nothing as per my understanding.

@rick: ” well, that would be the description of only one actor.”

How so?

The model obviously works for many queues with each consumer working as a producer and vice versa.

@Sushrut: No, please argue with the post. If your usecase describes shared data (tickets), then you cannot partition the solution in any way to not share data (at least that I know of).

More actors do not solve the problem.

And if your usecase does not involve sharing data, then well, why should you share data with any concurrency model?

@stephan – maybe I misunderstood, could be. Your use of the words ‘a queue’ led me to believe you thought there’s only one queue in an actor model.

Sharing is still possible, of course.

Writing should be done asynchronously, through the actor and will be performed synchronously by that same actor.

You can think of multiple solutions for reading. I would use event sourcing and local caching in the consuming actors. Also used in cqrs (& its circular architecture).

Actors are absolutely all about shared mutable state.

You’re right, actors do share their state because there exists a dependency between an actor’s state and the messages that it sends.

Of course, the exact representation of the state cannot (properly) be observed from the outside, but if an actor has state, it’s implicitly shared if the messages that it sends to other actors depend on its state.

@Runar: I’m not used to you agreeing with me – somehow :-) Thanks for sharing the idea about messages and dependency.

Cedric

I’m probably in-between about actors. I agree with your skepticism, though, and I think the value and simplicity of the actor model have been exaggerated.

Something that has always puzzled me is that actors do share a single synchronization point: their message inbox. Instead of having these locks spread over several synchronized methods (the Java way), you are now funneling all your methods in this single inbox. The claims are that locking in the inbox can be made very fast and is never a bottleneck, but I wonder.

@Cedric: Instead of my blog post I could have put up your comment. I agree with the in-between (and the post was not intended as against-actors, just against myths). I agree with the single synchronization point instead of spread across methods. And I wonder too.

lakemalcom

@Rick van der Arend, I agree that sticking to one-way messaging, no waiting, would remove concurrency hazards. But how would I simulate fork/join parallelism with actors in such a programming model? Particularly, how would I join actions? I would have to receive or to react, i.e. in either case resorting two-way messaging. So I would have to make really sure that actors down the line _always_ send back the response (be it normal or something to signify an error).

One could of course respond “if you need fork/join parallelism, use the fork/join framework”, sure enough. Which is part of the point, actors do not seem the universal be-all, end-all programming model for concurrency, and we (well, at least I) have yet to figure the precise cases where it is the best-fitting solution. If anyone has such a characterization, of when actors is the best choice over other programming models, I would be very interested in it.

@Cedric, @stephan, regarding the single synchronization point, well, one is free to spawn many actors, in effect striping that single lock.

mue

Hi funzel,

as promised my little comment.

Somehow I dislike the term actor. Communicating Sequential Processes (CSP) by Tony Hoare describes the idea better. Software based on this idiom consists out of a large number of light weighted processes processing messages sent to them sequentially. In Erlang/OTP each processes only has one inbox but a very flexible pattern matching, in Go goroutines can listen to multiple channels parallely while those channels can also be listened by multiple goroutines.

After a short time this way becomes a very natural kind of thinking. It is a very good base for concurrent software, but it’s not the panacea without any problems. Synchronous request with answers need a kind of request/response messaging which without timeouts can easily lead to deadlocks (A calls B calls C calls A). This can be dismantled by timeouts, like in Erlang/OTP, but here this means a new level of error handling complexity (is it a deadlock or just a real timeout, because one process has a high load).

So back to the myths:

(1) Actors encapsulate their internal states, yes, and they don’t share it directly. But state changes depend on the messages the actors receive. So I won’t call it “share nothing arch” but “share actors arch”.

(2) From my experiences it’s definitely a very simple idiom for the creation of massive concurrent applications. It removes many pitfalls and makes it easier to not forget semaphores or synchronized blocks. But a brings some new problems – single processing loop – and definitely doesn’t solve every problem (deadlocks, partitioning of problems). So one has to learn how to use actors/CSP/MPI the right way.

@Dimitris, I think that Actors are really just a stepping stone towards implementing a fork/join/map monad. See here for an implementation:

http://scalaz.googlecode.com/svn/continuous/latest/browse.sxr/scalaz/concurrent/Promise.scala.html

I’m just going to say some things like they’re facts, and we’ll see whether I know what I’m talking about or I’m going to get some extra learning today.

Discussing whether or not a two-actor system constitutes a shared-nothing architecture is a misapplication of the concept. Of course if you have one actor depending upon another, the first actor depends transitively on the second actor’s state– but that’s not the kind of sharing to which the phrase “shared nothing architecture” refers. That’s why nobody ever argues over whether a system with a single app server and a single database node is “shared nothing”; there’s only one app server, so with whom would it be sharing the database?

Whether or not an architecture is shared-nothing doesn’t really become a question until you have at least three actors.

Helpful diagram: http://imgur.com/6LJe5.png

@lakemalcom: James is clever, nice link. Although he tends towards pesonal attacks and doesn’t like me very much ;-)

@Logan: I did not talk about two actors but many actors. Assume N actors depend on one actor (TicketActor) for the context of the post.

@Mue: Thanks a lot for your take on this and some insights for me.

Wow, lots of answers here since yesterday when I gave the first one :)

Anyways, discussion seems to have been somewhat drifted toward implementation details and the “are actors the concurrency silver bullet” question, which wasn’t the original one and isn’t interesting either because of the obvious answer.

Going back to the discussed myths …
1) Are actors a shared nothing system? Yes, because actors don’t share state, but send messages instead: it’s true those messages may *depend* on internal state, but this doesn’t mean to *share* state.
2) Are they easier to get right because of that? It depends on your mindset and what you’re trying to accomplish. Once you shift your mind toward asynchronous message passing, actors will let you think in terms of message flows without caring about what to share and what to lock and how to do to avoid liveness problems, which is an advantage. But still, many prefer locks and explicit concurrency.

Obviously, you can implement actors in several ways, and you can also implement asynchronous systems that work similar to the actor one.
And obviously, you can misimplement and screw up everything even when using the actor model, no system will ever save us from our own mistakes.
But that’s another story ;)

Cheers!

Sergio B.

@Sergio: Again, 1) No, see James. If two actors share access to another actor which is holding state, then they are sharing state for any Non-Orwellian definition of “sharing state”.

(with the very senseful definition of state by James).

James identifies “state” with “application state”: obviously, any kind of useful application has state, and you have to manipulate such a state in order to accomplish something useful, regardless of your actual concurrency model. As a side note, the race condition outlined in his post is due to its oversimplified/poor interaction protocol, not the the actor model.

That said, when talking about “shared nothing architecture” in concurrency models (actors) or distributed systems (take Cassandra as an example), we don’t refer to global application state: we refer to the state, maybe memory is a more appropriate term, of a single actor/system. In such a case, and with such a state definition which isn’t Orwellian either, actors clearly don’t share state.

@Sergio: “That said, when talking about “shared nothing architecture” in concurrency models (actors) or distributed systems (take Cassandra as an example), we don’t refer to global application state: we refer to the state, maybe memory is a more appropriate term, [...]”

As James said, and I agree with him,
a.) This is Orwellian b/c noone else uses this term in that way
b.) Memory is irrelevant

See above then every Java object with sync methods and getters/setters also is a shared nothing architecture.

I don’t think we add anything new to the discussion. It boils down to:

Me,James,others: If two actors depend on the internal state of a third actor, they are sharing state.

You,Erlang community: If two actors depend on the internal state of a third actor, they are not sharing state.

Hi Stephan,

I half agree with you. From the point of view concurrent memory access, actors don’t share their internal state. This property is easy to implement in standard class with proper encapsulation and immutable method parameters/return values. If your looking at the state of all the actors and the dependencies between each other, I’d call that distributed state, not shared state. On the other hand, I agree with your assessment of the locking situation.

@Hiram: The usual claim is not:
“Share not internal state architecture”

but

“Share nothing architecture”

Noone would argue with the internal state claim.

RogerV

So followed all the discussion and thought might be learning something, but in the end it all seems to boil down to one of those debates about what the meaning of ‘is’ is, so far as shared state, et al.

The bottom line is that the Actor async messaging approach with queued access to actor state is a different way to program concurrent systems than others.

When I program in Google’s Go language with goroutines, my concurrent applications are entirely different in their structure than how I coded applications in the past with Java’s synchronized, util.concurrency library, etc.

Because I’ve been a heavy JMS developer for years building distributed systems, a messaging approach to concurrency via language innate features like goroutines was a very easy uptake. It’s faster for me to develop concurrent applications with this approach and not get bogged down trying to get things right as was the case with the previous approaches.

I wouldn’t argue that it’s an end-all solution for concurrent programming needs, but it’s a useful approach to add to the arsenal and can enable a developer to be more productive. More productive in the sense of how I became significantly more productive back in the day when I switched away from C++ to Java and C#.

@RogerV: “I wouldn’t argue that it’s an end-all solution for concurrent programming needs, but it’s a useful approach to add to the arsenal and can enable a developer to be more productive.”

Noone in this thread has argued that.

Ernesto

@Sergio

“That said, when talking about “shared nothing architecture” in concurrency models (actors) or distributed systems (take Cassandra as an example), we don’t refer to global application state: we refer to the state, maybe memory is a more appropriate term, of a single actor/system.”

Right.

@Stephan

“a.) This is Orwellian b/c noone else uses this term in that way”

I disagree, in Java Concurrency in Practice, which is by no means a standard, but we all can agree that is a relevant book in the subject, state is defined as the data inside an object “stored in state variables such as instance or static fields”, and the term shared state refers to state variables (read object’s variables) “that could be accessed by multiple threads”. So an Actor which only consumes/produces messages doesn’t share state according to these definition, which I think is the norm when talking about concurrency, at least in Java.

All quotes taken from Chapter 2, first page, in case anybody might want to check :)

@Ernesto

I have countless examples in books and academic papers regarding concurrent and distributed systems, defining state in terms of internal object/system state.
I esteem and respect Stephan very much, he’s a very nice person, but I have no interest in convincing someone who defines others’ point of view as “Orwellian”, so I’ll stop my discussion here.

@Sergio: On the Orwellian: This is from James and I agree, but

Orwellian, for those who use the “share nothing” term outwards to convince others of actors.

It’s more like cats and dogs. They speak different languages.

From the discussion above,what Erlang calls “share nothing” others would call “encapsulation” (see encapsulated Java examples etc.)

So using share-nothing inside Erlang is fine as it describes the fact in Erlang terms, using it outside knowing that others use the term differently (system as you call it), is Orwellian, I stand with that.

Marc

Stephan, are you sure that your ticketmanager is a good use-case/example for actors – or that at least your synchronous access to the # of tickets would’nt totally contradict the whole point of actors? With actors you would send a message to the ticketmanager to request a ticket and he would either return you a ticket (asynchronously!) or an error that none are available anymore and you’d have to watch it on youtube or look on ebay ;)

Shared state: Are actors part of the application state as a whole: hell yes. Do single actors share their local state: no – not if you and your application architecture comply to the whole idea of actors.

And with all due respect to James Iry and his vending machine: that example in context of actors is total b/s and Tim has said it quite well in
his comment: http://james-iry.blogspot.com/2009/04/erlang-style-actors-are-all-about.html?showComment=1253812155361#c3904292961745027682

@Marc: Not sure you would like to buy tickets asynchronously. But as I’ve said – perhaps it might be a good idea to read the post again ;-) async helps.

I know the actor community does not want to discuss usecases where you need to share state.

And Tim has no clue I assume what James wanted to illustrate – that if you have a usecase that needs to share state you can get race conditions and actors will not help you – no technology will help you if your use case needs state sharing. Obviously James example is not about sock dispensers.

Nexos
ScottHK

Actors work best to push data to a single worker thread, essentially creating a single-threaded program. I have found this is the best solution for 99% of my business apps.

Yes, Actors do not solve the synchronization problems for a true multi-threaded program. If you think about having multiple Actors communicating in an internet book store app the locking issues have not changed at all from other solutions.

In my tests BlockingQueue in Java creates a massive amount of context switching. Does it make sense to do a thread switch for every tiny message that comes in, and is there any easy way around this?

Leave a Reply

What people wrote somewhere else:

Just blogged “Actor Myths” http://bit.ly/9taBfT

This comment was originally posted on Twitter

@themue Perhaps you could comment on this? http://bit.ly/dnUH4t Would be nice – you have a deeper understanding than me probably

This comment was originally posted on Twitter

RT @codemonkeyism: Just blogged “Actor Myths” http://bit.ly/9taBfT

This comment was originally posted on Twitter

Stephan Schmidt: Actor Myths http://bit.ly/cOp6rB

This comment was originally posted on Twitter

RT @PlanetScala Stephan Schmidt: Actor Myths http://bit.ly/cOp6rB

This comment was originally posted on Twitter

[Scala] Actor Myths: Actors are the new concurrency. They are everywhere. People make bold claims about actors, an… http://bit.ly/aEU2YK

This comment was originally posted on Twitter

hunting again for controversial discussions ;) RT @codemonkeyism Just blogged “Actor Myths” http://bit.ly/9taBfT

This comment was originally posted on Twitter

RT @codemonkeyism: Just blogged “Actor Myths” http://bit.ly/9taBfT

This comment was originally posted on Twitter

RT @codemonkeyism: Just blogged “Actor Myths” http://bit.ly/9taBfT

This comment was originally posted on Twitter

@codemonkeyism Just added my comment to http://codemonkeyism.com/actor-myths/ #actors #erlang #golang

This comment was originally posted on Twitter

RT @PlanetScala: Stephan Schmidt: Actor Myths http://bit.ly/cOp6rB

This comment was originally posted on Twitter

Are some actor concurrency model foundations just myths? Read http://codemonkeyism.com/actor-myths and don’t miss comments inside.

This comment was originally posted on Twitter

Actor Myths: Actors are the new concurrency. They are everywhere. People make bold claims about actors, and while … http://bit.ly/cOp6rB

This comment was originally posted on Twitter

Code Monkeyism: Actor Myths http://goo.gl/1ZYR

This comment was originally posted on Twitter

RT @ingramchen: Code Monkeyism: Actor Myths http://goo.gl/1ZYR

This comment was originally posted on Twitter

My “actor myths” post made me realize, there are others I respect with my opinion, and the Erlang community is stramge http://bit.ly/dnUH4t

This comment was originally posted on Twitter

RT @codemonkeyism: My “actor myths” post made me realize, there are others I respect with my opinion, and the Erlang community is stramge http://bit.ly/dnUH4t

This comment was originally posted on Twitter

RT @codemonkeyism: My “actor myths” post made me realize, there are others I respect with my opinion, and the Erlang community is stramge http://bit.ly/dnUH4t

This comment was originally posted on Twitter

Code Monkeyism: Actor Myths: http://bit.ly/ave96e Comments: http://bit.ly/bDBekb

This comment was originally posted on Twitter

Code Monkeyism: Actor Myths http://bit.ly/9ISoyC

This comment was originally posted on Twitter

Actor Myths – http://su.pr/8DRwGW

This comment was originally posted on Twitter

Actor Myths http://bit.ly/cMbmtP

This comment was originally posted on Twitter

Code Monkeyism: Actor Myths – http://su.pr/8DRwGW

This comment was originally posted on Twitter

Code Monkeyism: Actor Myths: Actors are the new concurrency. They are everywhere. People make bold claims about ac… http://bit.ly/aCOM74

This comment was originally posted on Twitter

@jboner have you read this? http://bit.ly/bcDbbw – this guy is an infidel :)

This comment was originally posted on Twitter

Additional comments powered by BackType

Guide to CodeMonkeyism

Over the last 4 years I wrote many articles on this blog. To make it easier for you to find the relevant ones, I've organized them into topics.

Top 10

6 reasons why my VC funded startup did fail

Go Ahead: Next Generation Java Programming Style

Java Interview questions: Write a String Reverser

The dark side of NoSQL

7 Bad Signs not to Work for a Software Company or Startup

Is Java dead?

Scala vs. Clojure

Never, never, never use String in Java

No future for functional programming in 2008 – Scala, F# and Nu

Clojure vs Scala, Part 2

Java Developer

Is Java Dead?

Go Ahead: Next Generation Java Programming Style

Be careful with magical code

All variables in Java must be final

Never, never, never use String in Java

Bending Java: More readable code with methods that do nothing?

NoSQL Guy

NoSQL: The Dawn of Polyglot Persistence

The dark side of NoSQL

Essential storage tradeoff: Simple Reads vs. Simple Writes

Sharding destroys the goals of your relational database

The unholy legacy of databases

Startup/CTO

Development Dream Teams

6 reasons why my VC funded startup did fail

American vs. European style of Software Development

12 Things to Reduce Your Lead Time and Time to Market

The high cost of overhead when working in parallel

Essential storage tradeoff: Simple Reads vs. Simple Writes

Job Seeker

Another Good (Java) Interview Question

7 Bad Signs not to Work for a Software Company or Startup

Java Interview questions: Write a String Reverser (and use Recursion!)

Java Interview questions: Multiple Inheritance

As a Manager: What I value in developers

Top 10 Tips (+1) to Get a Pay Raise

Agilist

What Developers Need to Know About Agile

5 Practices Better to Change in Your Scrum Implementation

Scrum is not about engineering practices

ScrumMaster and ZenMaster: The joke of certification

What is Trans-Scrum?