Remove some unnecessary object creation and switch to HashSet for better performance. See #3308

This commit is contained in:
Björn Antonsson 2013-05-14 22:07:56 +02:00
parent 05ba6df5ac
commit 1a63ff7dbd
8 changed files with 29 additions and 25 deletions

View file

@ -215,7 +215,7 @@ class ActorSystemSpec extends AkkaSpec(ActorSystemSpec.config) with ImplicitSend
"reliably create waves of actors" in {
import system.dispatcher
implicit val timeout = Timeout(30 seconds)
implicit val timeout = Timeout((20 seconds).dilated)
val waves = for (i 1 to 3) yield system.actorOf(Props[ActorSystemSpec.Waves]) ? 50000
Await.result(Future.sequence(waves), timeout.duration + 5.seconds) must be === Seq("done", "done", "done")
}

View file

@ -365,7 +365,7 @@ abstract class ActorModelSpec(config: String) extends AkkaSpec(config) with Defa
def flood(num: Int) {
val cachedMessage = CountDownNStop(new CountDownLatch(num))
val stopLatch = new CountDownLatch(num)
val waitTime = (30 seconds).dilated.toMillis
val waitTime = (20 seconds).dilated.toMillis
val boss = system.actorOf(Props(new Actor {
def receive = {
case "run" for (_ 1 to num) (context.watch(context.actorOf(props))) ! cachedMessage

View file

@ -301,8 +301,7 @@ private[akka] object ActorCell {
final val emptyBehaviorStack: List[Actor.Receive] = Nil
final val emptyActorRefSet: Set[ActorRef] = immutable.TreeSet.empty
final val emptyActorRefMap: Map[ActorPath, ActorRef] = immutable.TreeMap.empty
final val emptyActorRefSet: Set[ActorRef] = immutable.HashSet.empty
final val terminatedProps: Props = Props(() throw new IllegalActorStateException("This Actor has been terminated"))

View file

@ -96,7 +96,7 @@ abstract class ActorRef extends java.lang.Comparable[ActorRef] with Serializable
*/
final def compareTo(other: ActorRef) = {
val x = this.path compareTo other.path
if (x == 0) this.path.uid compareTo other.path.uid
if (x == 0) if (this.path.uid < other.path.uid) -1 else if (this.path.uid == other.path.uid) 0 else 1
else x
}

View file

@ -64,7 +64,7 @@ object Props {
*
* Scala API.
*/
def apply[T <: Actor: ClassTag](): Props = apply(implicitly[ClassTag[T]].runtimeClass)
def apply[T <: Actor: ClassTag](): Props = apply(defaultDeploy, implicitly[ClassTag[T]].runtimeClass, Vector.empty)
/**
* Returns a Props that has default values except for "creator" which will be a function that creates an instance
@ -136,8 +136,11 @@ object Props {
@SerialVersionUID(2L)
case class Props(deploy: Deploy, clazz: Class[_], args: immutable.Seq[Any]) {
// the constructor can't be serialized, but needs to be a lazy val to be initialized after deserialization
@transient
private lazy val constructor = Reflect.findConstructor(clazz, args)
// validate constructor signature; throws IllegalArgumentException if invalid
Reflect.findConstructor(clazz, args)
constructor
/**
* No-args constructor that sets all the default values.
@ -250,16 +253,18 @@ case class Props(deploy: Deploy, clazz: Class[_], args: immutable.Seq[Any]) {
* used within the implementation of [[IndirectActorProducer#produce]].
*/
def newActor(): Actor = {
Reflect.instantiate(clazz, args) match {
Reflect.instantiate(constructor, args) match {
case a: Actor a
case i: IndirectActorProducer i.produce()
case _ throw new IllegalArgumentException(s"unknown actor creator [$clazz]")
}
}
// don't serialize the class but reinitialize it after deserialization
@transient
private lazy val cachedActorClass: Class[_ <: Actor] = {
if (classOf[IndirectActorProducer].isAssignableFrom(clazz)) {
Reflect.instantiate(clazz, args).asInstanceOf[IndirectActorProducer].actorClass
Reflect.instantiate(constructor, args).asInstanceOf[IndirectActorProducer].actorClass
} else if (classOf[Actor].isAssignableFrom(clazz)) {
clazz.asInstanceOf[Class[_ <: Actor]]
} else {

View file

@ -184,7 +184,7 @@ private[akka] trait Children { this: ActorCell ⇒
// this name will either be unreserved or overwritten with a real child below
val actor =
try {
val childPath = (cell.self.path / name).withUid(ActorCell.newUid())
val childPath = new ChildActorPath(cell.self.path, name, ActorCell.newUid())
cell.provider.actorOf(cell.systemImpl, props, cell.self, childPath,
systemService = systemService, deploy = None, lookupDeploy = true, async = async)
} catch {

View file

@ -39,12 +39,11 @@ private[akka] trait DeathWatch { this: ActorCell ⇒
a
}
protected def receivedTerminated(t: Terminated): Unit = {
protected def receivedTerminated(t: Terminated): Unit =
if (terminatedQueued(t.actor)) {
terminatedQueued -= t.actor // here we know that it is the SAME ref which was put in
receiveMessage(t)
}
}
/**
* When this actor is watching the subject of [[akka.actor.Terminated]] message
@ -65,21 +64,17 @@ private[akka] trait DeathWatch { this: ActorCell ⇒
// TODO this should be removed and be replaced with `watching.contains(subject)`
// when all actor references have uid, i.e. actorFor is removed
private def watchingContains(subject: ActorRef): Boolean = {
private def watchingContains(subject: ActorRef): Boolean =
watching.contains(subject) || (subject.path.uid != ActorCell.undefinedUid &&
watching.contains(new UndefinedUidActorRef(subject)))
}
// TODO this should be removed and be replaced with `set - subject`
// when all actor references have uid, i.e. actorFor is removed
private def removeFromSet(subject: ActorRef, set: Set[ActorRef]): Set[ActorRef] = {
val removed = if (set(subject)) set - subject else set
if (subject.path.uid != ActorCell.undefinedUid)
removed - new UndefinedUidActorRef(subject)
else removed filterNot (_.path == subject.path)
}
private def removeFromSet(subject: ActorRef, set: Set[ActorRef]): Set[ActorRef] =
if (subject.path.uid != ActorCell.undefinedUid) (set - subject) - new UndefinedUidActorRef(subject)
else set filterNot (_.path == subject.path)
protected def tellWatchersWeDied(actor: Actor): Unit = {
protected def tellWatchersWeDied(actor: Actor): Unit =
if (!watchedBy.isEmpty) {
try {
def sendTerminated(ifLocal: Boolean)(watcher: ActorRef): Unit =
@ -103,9 +98,8 @@ private[akka] trait DeathWatch { this: ActorCell ⇒
watchedBy foreach sendTerminated(ifLocal = true)
} finally watchedBy = ActorCell.emptyActorRefSet
}
}
protected def unwatchWatchedActors(actor: Actor): Unit = {
protected def unwatchWatchedActors(actor: Actor): Unit =
if (!watching.isEmpty) {
try {
watching foreach { // ➡➡➡ NEVER SEND THE SAME SYSTEM MESSAGE OBJECT TO TWO ACTORS ⬅⬅⬅
@ -117,7 +111,6 @@ private[akka] trait DeathWatch { this: ActorCell ⇒
unsubscribeAddressTerminated()
}
}
}
protected def addWatcher(watchee: ActorRef, watcher: ActorRef): Unit = {
val watcheeSelf = watchee == self

View file

@ -50,7 +50,14 @@ private[akka] object Reflect {
* Calls findConstructor and invokes it with the given arguments.
*/
private[akka] def instantiate[T](clazz: Class[T], args: immutable.Seq[Any]): T = {
val constructor = findConstructor(clazz, args)
instantiate(findConstructor(clazz, args), args)
}
/**
* INTERNAL API
* Invokes the constructor with the the given arguments.
*/
private[akka] def instantiate[T](constructor: Constructor[T], args: immutable.Seq[Any]): T = {
constructor.setAccessible(true)
try constructor.newInstance(args.asInstanceOf[Seq[AnyRef]]: _*)
catch {