5
votes

Suppose I have an actor that has a single field. 99 out of every 100 messages to an actor read the value, and the 100th updates the value. In this case, I would like to process reads in parallel. In other words, how can I achieve the performance of Read/Write locks using Actors? Is this practical with Scala-standard actors or Akka? Or am I missing the point of actors :)

Update: fixed confusing language, sorry

4
Aren't all message to the actors read only (immutable)? The actor receives a message and does some processing depending on what the message was. If required, it sends a message to another actor as the part of processing.Abhinav Sarkar
Yes, the messages are immutable. Imagine the common example of a counter/incrementer as an actor: I'm wondering if reading the current value can be non-blocking for other read operations.Adam Rabung

4 Answers

6
votes

[Disclaimer: I'm the PO of Akka]

I suggest using Agents instead, the read can be done at any point, but only one write at a time.

http://doc.akkasource.org/agents-scala

EDIT: http://doc.akka.io/docs/akka/2.1.0/scala/agents.html (try this link)

6
votes

You're quite possibly missing the point of actors. I'm assuming you want an actor to which you send a query, and then it sends back a response. There's a fair amount of machinery involved in sending an actor a message, processing it, and sending a response back. The actual generation of the response message will be created as a task and submitted to a thread pool. Between the message queue and the thread pool there are multiple places that require locks or at best CAS operations. Usually the point is that the actor will do some work off in a separate thread based on that message.

If you just want to read and rarely write data (such as incrementing a counter, or access in a value in a map) you'll be much better off using an appropriate class from java.util.concurrent.

3
votes

I assume you mean that all messages are immutable and that almost all messages do not mutate the state of the actor. In this case, actors are probably not the best choice of design. Actors allow you to manage any mutable state as if you were dealing with single threaded code.

Effectively, each actor has a mailbox to which messages are sent and then processed one at a time. In your scenario, this would be quite wasteful. As suggested, using something from java.util.concurrent would be most effective.

2
votes

Actors are designed to process messages serially. This makes them easy to reason about: you get one message at a time, so any variables in the actor (as long as they are not mutated by anyone else) can be modified without thinking about concurrency. Is this the most efficient method? Absolutely not! But somewhat inefficient code that works correctly is almost always better than highly efficient code that is broken.

What you are asking for is the exact opposite: you want to think explicitly about concurrency ("I know that 99% of accesses will be reads and thus can occur in parallel!") in order to gain processing speed. In this case, you probably want to use java.util.concurrent.locks.ReentrantReadWriteLock to directly control access to a mutable variable (if the type of access found in java.util.concurrent.atomic._ doesn't work for you). Just remember that you now have taken on the burden of getting locking right, and be appropriately careful.