views:

278

answers:

2

I have been looking at the Actor Model for a while now. To me it seems to be just another approach towards concurrent programming with its own upsides and downsides.

It certainly does not guarantee deadlock-free environment. A can wait for a message from B while B waits for a message from A. I don't know if we can say the actors approach makes it more difficult to run into deadlock situations "if programmed correctly". So far I haven't seen any widely accepted literature on how actors should be designed. So I find it hard to blame this on bad programming.

There is no shared state between actors. If 1000 actors want to update a shared variable at the same time, they simply send non-blocking messages. Threads on the other hand will have to block. On the other hand, what if a process wants to be sure that the shared variable has been updated before moving on? A thread wouldn't have to worry because it blocks until the update is done while an actor will have to wait for a "update done" message. Besides, it is possible to program threads that put updates in a queue instead of blocking - effectively achieving what actors do.

I asked before the solution to the problem of a producer producing items in a much faster rate than a consumer can consume (for the Scala language). This may result in out of memory error. You can see the post to see proposed solutions. Fine, there are solutions, but most of our solutions require us to do some sort of synchronization like this. I haven't seen any scenarios so far where actors can run off and do their work independently without having to synchronize with other actors.

Erlang, a functional programming language, uses actors. Maybe this programming paradigm helps define problems to be suitable for actors?

We can point out more pros and cons but my question to stackoverflow is: given some concurrency problem, what would you look for to decide whether to use actors or not? Do you think the decision matters at all?

Edit Although I accepted the first answer, I encourage users to read the second answer as well. Still hoping to get more answers.

+2  A: 

Given some concurrency problem, what would you look for to decide whether to use actors or not?

First I would look to define the problem... is the primary motivation a speedup of a nested for loop or recursion? If so a simple task based approach or parallel loop approach will likely work well for you (rather than actors).

However if you have a more complex system that involves dependencies and coordinating shared state, then an actor approach can help. Specifically through use of actors and message passing semantics you can often avoid using explicit locks to protect shared state by actually making copies of that state (messages) and reacting to them.

You can do this quite easily with the classic synchronization problems like dining philosophers and the sleeping barbers problem. But you can also use the 'actor' to help with more modern patterns, i.e. your facade could be an actor, your model view and controller could also be actors that communicate with each other.

Another thing that I've observed is that actor semantics are learnable by most developers and 'safer' than their locked counterparts. This is because they raise the abstraction level and allow you to focus on coordinating access to that data rather than protecting all accesses to the data with locks. As an example, imagine that you have a simple class with a data member. If you choose to place a lock in that class to protect access to that data member then any methods on that class will need to ensure that they are accessing that data member under the lock. This becomes particularly problematic when others (or you) modify the class at a later date, they have to remember to use that lock.

On the other hand if that class becomes an actor and the data member becomes a buffer or port you communicate with via messages, you don't have to remember to take the lock because the semantics are built into the buffer and you will very explicitly know whether you are going to block on that based on the type of the buffer.

-Rick

Rick
+1  A: 

The usage of Actor is "natural" in at least two cases:

  1. When you can decompose your problem in a set of independent tasks.
  2. When you can decompose your problem in a set of tasks linked by a clear worflow (ie. dataflow programming).

For instance, if you process complex data using a series of filters, it is easy to use a pipeline of actors where each actor receives data from an upstream actor and sets data to a downstream actor.

Of course this data-flow must not be linear and if a step is slow in your pipeline, you can use instead a pool of actors doing the same job. Another way of solving the load balancing problems, would be to use instead a demand-driven approach organised with a kind of virtual Kanban system.

Of course you will need synchronization between actors in almost all interesting cases, but contrary to classic multi-thread approach, this synchronization is really "concrete". You can imagine guys in a factory, imagine possible problems (workers run out of job to do, upstream operations is too fast and intermediate products need a huge storage place, etc.) By analogy, you can then find a solution more easily.

paradigmatic
To add to your point, one of the advantages of object oriented programming is encapsulation of data and related functions. However, one still needs to "give life" to an object by calling one of its methods. We have a separate view of objects and processes there. Actors on the other hand are processes in their own right. This makes it easy to relate them to the real world.
tilish