What I meant was that of course the number of messages per actor goes down if they are contending for the same cores. (Ignoring the effects of cache coherence overhead here)
Cheers,
V
I'll see if I have some time for tests tomorrow.
As for receive:react, I thought like you and used react as first choice ; result is five times longer!
Not what I expected!
Don't forget, unlike many tests around I'm not having hundreds or thousands of actors exchanging thousands or hundreds messages. I'm having but two actors exchanging a lot of messages in a synchroneous way. Don't know if that changes something. Well, from what I read, I still should have better perfs.
Yves
Le mardi 16 octobre 2012 21:41:26 UTC+2, rkuhn a écrit :Hi Yves,
On 16 okt 2012, at 21:19, yves <yves....@gmail.com> wrote:
> Oh and by the way, I don't know if the 3 million messages per second measured correspond to a ping-pong situation which is my case.
> Has any measure been done for such a scenario ?
>
Yes, the number Viktor quoted was from a ping-pong test. The scala.actors may well be your performance bottleneck, especially if you are using receive{} instead of react{} (which I assume due to your talking about threads). And even react{} is a lot slower than Akka actors due to blocking synchronization. I'd love to hear about performance results when switching implementations, if you have the time.
background: waking up a thread is horribly expensive, the only cure is to never park() it in the first place, i.e. instead of having threads receive messages dispatch your actors across threads which are shared and thus mostly busy; that is what Akka does.
Regards,
Roland Kuhn
Typesafe — The software stack for applications that scale
twitter: @rolandkuhn
Yves
Ah ah!
That must be it.
But I cannot go further : typesafe requires install rights which I don't have and won't be given.
That means I will not be able to test akka.
Too bad.
Yves
I've read the documentation.
The problem I have looks absolutely clear; my project would compile but for the fact that it seems to require a third party library (typesafe) which I can't install. If you read the error messages I have, you'll agree with me.
Why Akka requires it, I don't know. Maybe a forgotten dependency of some sort. I shouldn't need it, because typesafe is seemingly used to brideg Akka with Play (whatever that is...)
Maybe that's an artefact due to the version I used (scala 2.10M7, which isn't certainly the wistest to do...)
Anyway, it's absolutely clear that this is the only problem. The actor library is on may path, and I got normal compile errors till I should have none. And then, I get that strange messages.
Yves
Some additional info:
~15s using receive and 1000000 messages (i.e. 70000 messages per second)
~10s using react and 1000000 messages (i.e. 100000 messages per second)
Intel core i5-2400 @3.10 GHz
I'm far from 3000000 messages per second! (factor 30 in the best case)
I still have a shutdown problem.
}
def main(args:Array[String]):Unit = {
start()
}
}
A dramatic performance increase stems from not calling sys.actorOf(Props(()=>new User(out),"out")), and simply removing the name sys.actorOf(Props(()=>new User(out)))
Throughput now is about 2*330000 messages per second, which is a threefold increase over the previous test!
Such a small change for such a big gain!!!
If I can still gain a x2 (why not), I'll be close to my objective!
Yves
last Akka version.
import akka.actor.{Actor,ActorRef,Terminated,ActorSystem,Props}
object cont
object abt
object term
final class Out(val user:ActorRef) extends Actor {
var i=0
override def preStart = { println(user); send }
def send = { i+=1; user ! "info "+i; if (i==100*Main.m) { user ! term; context.stop(self) } }
def receive() = {
case `cont` => if (i%Main.m==0) println(s"out = ${Thread.currentThread.getName}"); send
case `abt` => i+=10; send
case Terminated(_) => context.stop(self)
}
override def toString = "out"
}
final class User(val out:ActorRef) extends Actor {
var i = 0
var t:Long = 0
override def preStart = { println(out); t = System.currentTimeMillis }
def receive() = {
case s:String => i+=1; if (i%Main.m==0) println(s"user = ${Thread.currentThread.getName} => $s"); out ! (if (i%(10*Main.m-1)==0) abt else cont)
case `term` => context.stop(self)
case Terminated(_) => context.stop(self)
}
override def postStop = { println(s"time ${System.currentTimeMillis-t} $i messages processed ${i/((System.currentTimeMillis-t)/1000)} messages/second") }
override def toString = "user"
}
object Main {
val m=10000
def start():Unit = {
val sys = ActorSystem.create
var out:ActorRef = null
var user=sys.actorOf(Props(()=>new User(out)))
out=sys.actorOf(Props(()=>new Out(user)))
}
def main(args:Array[String]):Unit = {
start()
}
}
I still have a shutdown problem.
A dramatic performance increase stems from not calling sys.actorOf(Props(()=>new User(out),"out")), and simply removing the name sys.actorOf(Props(()=>new User(out)))
Throughput now is about 2*330000 messages per second, which is a threefold increase over the previous test!
Such a small change for such a big gain!!!
If I can still gain a x2 (why not), I'll be close to my objective!
Roland Kuhn
Typesafe – The software stack for applications that scale.
twitter: @rolandkuhn
@Viktor: That was completely unintentional, what was rude about it?
Well, 'it makes no sense' made me feel like fool. :)
Thanks!
Hi Roland,
I appreciate your very explicit explanations.
I'm having 300000, but using an i5'2400 @ 3.1GHz. That might possibly make the difference.
I'm not new in multithreading, but have little background on Actors, except that they look very easy to use. I'll remember all that you write ; tremendously usefull stuff there.
In my new code, I don't see the name making any difference. I wonder what was the artefact that caused this problem in the older versions of my code. Anyway, as you write, it was not correct according to the Actors style, and this might have had some difficult to understand consequences.
I also know that this test is not nice, with only one message flying at a time! But in real life (my life anyway), many things happen that way. Still, it's useful to put the producer on one Actor and the Consumer on another rather than having the producer directly invoke the consumer (when that is feasible, which is not always the case.) ; that's why I wrote this test, to understand how much CPU I was going to lose by using this paradigm.
Looking back at the original question, I"m not sure why the consumer and the producer chat to one another so much - depending on the exact scenario, I might either just send ALL THE THINGS to the consumer as fast as possible and let them sit in the mailbox (which will then take advantage of batching and save you some overhead) or I might have the consumer ask for a sized batch of stuff.Equally, I might do a little more parallelism in the pipeline, if the problem is amenable. For example, if the preprocessing done by the producer can be parallelisedInput -> n*Preprocessors -> Gatherer (that puts things back into order) -> Consumer (possibly multiple of these too?)Anyway, not much that can be said without knowing the actual task, but food for thought perhaps :)
So the decoupling thing isn't really anything to do with actors because you could just do the same thing with plain old classes. Likewise, your consumer model isn't directly related to actors either.
You're also not getting any real benefit from multithreading here - you've described an inherently sequential system, so I'm not sure you get any upside in this particular case.
Roland's argument about error handling is a very good one, as is yours about learning through doing.
It's worthwhile understanding what you are and aren't getting from switching to actors though.
The problem is that I have on one side a parser (producer) and the other a consumer.
The parser should in most of the time ignore the tokens (i.e. pass in a very fast mode where it doesn't even form them!)
But it doesn't know what is useful for the consumer.