Scala's primary concurrency construct is actors. Actors are basically concurrent processes that communicate by exchanging messages. Actors can also be seen as a form of active objects where invoking a method corresponds to sending a message. The Scala Actors library provides both asynchronous and synchronous message sends.
Actors are normal objects that are created by instantiating subclasses of the Actor class. We define the behavior of actors by subclassing Actor and implementing its abstract act method.
Every actor has a “mailbox” of its incoming messages which is represented as a queue. It can work sequentially through the messages in itsmailbox, or search for messages matching some pattern.
Reply messages are sent using syntax of the form Destination ! SomeMessage. ! is used here as a binary operator with an actor and a message as arguments. The invocation of the ! method of the destination actor with the givenmessage as parameter.
1. Receive Model
Process messages repeatly,place receive inside of while(..)
class Ping(count: int, pong: Actor) extends Actor { def act() { var pingsLeft = count - 1 pong ! Ping while (true) { receive { case Pong => if (pingsLeft % 1000 == 0) Console.println("Ping: pong") if (pingsLeft > 0) { pong ! Ping pingsLeft -= 1 } else { Console.println("Ping: stop") pong ! Stop exit() } } } } }
2. React Model
- Never return;
- Process messages repeatedly, use react inside of loop, instead of while(..);
- Reuse threads, so more efficiently than receive.
Actors are executed on a thread pool. Initially, there are 4 worker threads. The thread pool grows if all worker threads are blocked but there are still remaining tasks to be processed. Ideally, the size of the thread pool corresponds to the number of processor cores of the machine.
When actors call thread-blocking operations, such as receive (or even wait), the worker thread that is executing the current actor (self) is blocked. This means basically that the actor is represented as a blocked thread. Depending on the number of actors you want to use, you might want to avoid this, since most JVMs cannot handle more than a few thousand threads on standard hardware.
Thread-blocking operations can be avoided by using react to wait for new messages (the event-based pendant ofreceive). However, there is a (usually small) price to pay: react never returns. In practice, this means that at the end of a reaction to a message, one has to call some function that contains the rest of the actor's computation. Note that using react inside a while loop does not work! However, since loops are common there is special library support for it in form of a loop function.
Make the above example Thread-less
def act() { var pongCount = 0 loop { react { case Ping => if (pongCount % 1000 == 0) Console.println("Pong: ping "+pongCount) sender ! Pong pongCount = pongCount + 1 case Stop => Console.println("Pong: stop") exit() } } }
The best way to guarantee thread-safe is only using immutable object as message objects.
In message class, only define "val" referring to immutable object. A simple approach is to use "case class", and make all "val" immutable.
If you have to send a mutable object to the other actors, send an obj.clone, instead of obj.
Java Thread | Scala actor |
share data and lock | share nothing |
Every object with a monitor,to watch multi-thread access to shared data | no shared data, actors communicate with messages |
lock code block by using keyword synchronized | |
deadloack issue | |
sequence execution in each thread | sequence execution in each actor |
http://www.scala-lang.org/old/node/242
No comments:
Post a Comment