=act Optimize BehaviorBuilder and ReceiveBuilder's BuiltBehavior into array based. (#31325)

This commit is contained in:
kerr 2022-04-26 22:02:09 +08:00 committed by GitHub
parent a4f8890c7b
commit 2c896fca26
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 51 additions and 44 deletions

View file

@ -0,0 +1,3 @@
# #30445 performance improvements for typed javadsl message matchers
ProblemFilters.exclude[IncompatibleMethTypeProblem]("akka.actor.typed.javadsl.BuiltReceive.this")
ProblemFilters.exclude[IncompatibleMethTypeProblem]("akka.actor.typed.javadsl.BuiltBehavior.this")

View file

@ -34,7 +34,9 @@ final class BehaviorBuilder[T] private (messageHandlers: List[Case[T, T]], signa
/** /**
* Build a Behavior from the current state of the builder * Build a Behavior from the current state of the builder
*/ */
def build(): Behavior[T] = new BuiltBehavior(messageHandlers.reverse, signalHandlers.reverse) def build(): Behavior[T] = {
new BuiltBehavior[T](messageHandlers.reverse.toArray, signalHandlers.reverse.toArray)
}
/** /**
* Add a new case to the message handling. * Add a new case to the message handling.
@ -157,6 +159,7 @@ object BehaviorBuilder {
private val _empty = new BehaviorBuilder[Nothing](Nil, Nil) private val _empty = new BehaviorBuilder[Nothing](Nil, Nil)
// used for both matching signals and messages so we throw away types after they are enforced by the builder API above // used for both matching signals and messages so we throw away types after they are enforced by the builder API above
/** INTERNAL API */ /** INTERNAL API */
@InternalApi @InternalApi
private[javadsl] final case class Case[BT, MT]( private[javadsl] final case class Case[BT, MT](
@ -177,23 +180,25 @@ object BehaviorBuilder {
* INTERNAL API * INTERNAL API
*/ */
@InternalApi @InternalApi
private final class BuiltBehavior[T](messageHandlers: List[Case[T, T]], signalHandlers: List[Case[T, Signal]]) private final class BuiltBehavior[T](messageHandlers: Array[Case[T, T]], signalHandlers: Array[Case[T, Signal]])
extends ExtensibleBehavior[T] { extends ExtensibleBehavior[T] {
override def receive(ctx: TypedActorContext[T], msg: T): Behavior[T] = receive(msg, messageHandlers) override def receive(ctx: TypedActorContext[T], msg: T): Behavior[T] = receive(msg, messageHandlers, 0)
override def receiveSignal(ctx: TypedActorContext[T], msg: Signal): Behavior[T] = override def receiveSignal(ctx: TypedActorContext[T], msg: Signal): Behavior[T] = receive(msg, signalHandlers, 0)
receive(msg, signalHandlers)
@tailrec @tailrec
private def receive[M](msg: M, handlers: List[Case[T, M]]): Behavior[T] = private def receive[M](msg: M, handlers: Array[Case[T, M]], idx: Int): Behavior[T] = {
handlers match { if (handlers.length == 0) {
case Case(cls, predicate, handler) :: tail => Behaviors.unhandled[T]
} else {
val Case(cls, predicate, handler) = handlers(idx)
if ((cls.isEmpty || cls.get.isAssignableFrom(msg.getClass)) && (predicate.isEmpty || predicate.get.apply(msg))) if ((cls.isEmpty || cls.get.isAssignableFrom(msg.getClass)) && (predicate.isEmpty || predicate.get.apply(msg)))
handler(msg) handler(msg)
else receive(msg, tail) else if (idx == handlers.length - 1)
case Nil =>
Behaviors.unhandled[T] Behaviors.unhandled[T]
else
receive(msg, handlers, idx + 1)
}
} }
} }

View file

@ -4,16 +4,13 @@
package akka.actor.typed.javadsl package akka.actor.typed.javadsl
import scala.annotation.tailrec import akka.actor.typed.{ Behavior, MessageAdaptionFailure, Signal }
import akka.actor.typed.{ Behavior, Signal }
import akka.actor.typed.MessageAdaptionFailure
import akka.annotation.InternalApi import akka.annotation.InternalApi
import akka.japi.function.{ Function => JFunction } import akka.japi.function.{ Creator, Function => JFunction, Predicate => JPredicate }
import akka.japi.function.{ Predicate => JPredicate }
import akka.japi.function.Creator
import akka.util.OptionVal import akka.util.OptionVal
import scala.annotation.tailrec
/** /**
* Mutable builder used when implementing [[AbstractBehavior]]. * Mutable builder used when implementing [[AbstractBehavior]].
* *
@ -33,8 +30,7 @@ final class ReceiveBuilder[T] private (
val builtSignalHandlers = val builtSignalHandlers =
if (signalHandlers.isEmpty) defaultSignalHandlers[T] if (signalHandlers.isEmpty) defaultSignalHandlers[T]
else (adapterExceptionSignalHandler[T] :: signalHandlers).reverse else (adapterExceptionSignalHandler[T] :: signalHandlers).reverse
new BuiltReceive[T](messageHandlers.reverse.toArray, builtSignalHandlers.toArray)
new BuiltReceive[T](messageHandlers.reverse, builtSignalHandlers)
} }
/** /**
@ -196,24 +192,27 @@ object ReceiveBuilder {
*/ */
@InternalApi @InternalApi
private final class BuiltReceive[T]( private final class BuiltReceive[T](
messageHandlers: List[ReceiveBuilder.Case[T, T]], messageHandlers: Array[ReceiveBuilder.Case[T, T]],
signalHandlers: List[ReceiveBuilder.Case[T, Signal]]) signalHandlers: Array[ReceiveBuilder.Case[T, Signal]])
extends Receive[T] { extends Receive[T] {
import ReceiveBuilder.Case import ReceiveBuilder.Case
override def receiveMessage(msg: T): Behavior[T] = receive[T](msg, messageHandlers) override def receiveMessage(msg: T): Behavior[T] = receive[T](msg, messageHandlers, 0)
override def receiveSignal(msg: Signal): Behavior[T] = receive[Signal](msg, signalHandlers) override def receiveSignal(msg: Signal): Behavior[T] = receive[Signal](msg, signalHandlers, 0)
@tailrec @tailrec
private def receive[M](msg: M, handlers: List[Case[T, M]]): Behavior[T] = private def receive[M](msg: M, handlers: Array[Case[T, M]], idx: Int): Behavior[T] = {
handlers match { if (handlers.length == 0) {
case Case(cls, predicate, handler) :: tail => Behaviors.unhandled[T]
} else {
val Case(cls, predicate, handler) = handlers(idx)
if ((cls.isEmpty || cls.get.isAssignableFrom(msg.getClass)) && (predicate.isEmpty || predicate.get.test(msg))) if ((cls.isEmpty || cls.get.isAssignableFrom(msg.getClass)) && (predicate.isEmpty || predicate.get.test(msg)))
handler(msg) handler(msg)
else receive[M](msg, tail) else if (idx == handlers.length - 1)
case _ => Behaviors.unhandled[T]
Behaviors.unhandled else
receive(msg, handlers, idx + 1)
}
} }
} }