This time, I continue to study the application of actor. I found that the advance example about actor in Scala-Lang is very representative. So I took the time to study this example, I have added some key debug information to my corrected code, because the original version cannot run on scala2.8:
import scala.actors._
import scala.actors.Actor._
object Message {
def main (args: Array [String]) {
val n = 3
var k = 0
val nActors = 500
val finalSum = n * nActors
def beh (next: Actor, sum: Int) {
k = k + 1
react {
case value: Int =>
val j = value + 1; val nsum = sum + j
println (Thread.currentThread (). getId () + "nSum:" + nsum + ", value:" + value + ", sum:" + sum)
if (next == null && nsum> = finalSum) {
println ("End");
System.exit (0)
}
else {
if (next! = null) next! j
// react never return, so must call some code to continue
beh (next, nsum)
}
}
}
def actorChain (i: Int, a: Actor): Actor =
if (i> 0) actorChain (i-1, actor (beh (a, 0))) else a
val firstActor = actorChain (nActors, null)
println ("# call times:" + k);
var i = n; while (i> 0) {firstActor! 0; i-= 1}
println ("Let's go!");
}
}
The intention of this example is to use the multi-thread technique to calculate ++ operations until the target value finalSum is reached. The first thing to do is to create 500 actor objects recursively, using the syntax actor {body}: Unit. Each actor has a reference to the one created earlier, so that you can test the two actors to send messages to each other, just like drumming That effect.
When I started running, I started with firstActor. I noticed that initially I sent 3 messages to firstActor at the same time, each time an Int: 0. Then, when receiving the message, I specially printed the ID of the current thread and recorded each The value of key operation parameters. What may be puzzling is the use of react {}, and beh in else calls itself recursively. Generally speaking, we use receive or receiveWithin in the actor to receive messages, but these two methods have a fatal weakness, that is, each time we receive a message, we must use a new Thread, so if we use receive or receiveWithin to receive News, then you will see hundreds of Thread
ID. The following gives a code snippet using the receive and receiveWithin versions: (Note that receiveWithin must add TIMEOUT case, otherwise it will not run)
// receiveWithin
receiveWithin (1000) {
case value: Int =>
val j = value + 1; val nsum = sum + j
println (Thread.currentThread (). getId () + "nSum:" + nsum + ", value:" + value + ", sum:" + sum)
if (next == null && nsum> = finalSum) {
println ("End");
System.exit (0)
}
else {
if (next! = null) next! j
}
case TIMEOUT =>
System.exit (-1);
}
}
// receive version
receive {
case value: Int =>
val j = value + 1; val nsum = sum + j
println (Thread.currentThread (). getId () + "nSum:" + nsum + ", value:" + value + ", sum:" + sum)
if (next == null && nsum> = finalSum) {
println ("End");
System.exit (0)
}
else {
if (next! = null) next! j
}
}
}
So for performance reasons, react is used here, because it uses a more reasonable way to receive tasks to apply for Thread resources. Multiple messages are sent and received by the total thread pool to arrange the optimal thread Quantity to perform. I saw 4 different Thread IDs on my machine. In addition, one of the characteristics of using react is that it executes the case every time, and does not return anything, which means that the code cannot continue to go down. At this time, a common practice is to recursively call itself containing react, so that it will return to the starting point of react, and then wait for the thread pool to arrange any Thread to receive the task and complete the processing of the message.
Due to the use of react, only a small amount of Thread resources are used to repeatedly process a large number of messages. The final value calculation exceeds finalSum and End successfully exits. On the author's machine, the value of call times will change and the number of times of execution is similar. This is because the processing of many messages is received by a random Thread object, which may be caused by next! J, then this Thread can obtain the current beh object context and the value of sum, nSum; at the same time, it may also be recursive Called by beh (next, nSum), then this Thread gets another set of context and variable values. In short, whoever comes to finalSum first, the program ends. This value can be carefully analyzed through the log printed by the author, especially compared with the receive and receiveWithin versions, I believe you will gain something.