=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,12 +34,14 @@ 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.
* *
* @param type type of message to match * @param type type of message to match
* @param handler action to apply if the type matches * @param handler action to apply if the type matches
* @tparam M type of message to match * @tparam M type of message to match
* @return a new behavior builder with the specified handling appended * @return a new behavior builder with the specified handling appended
@ -50,8 +52,8 @@ final class BehaviorBuilder[T] private (messageHandlers: List[Case[T, T]], signa
/** /**
* Add a new predicated case to the message handling. * Add a new predicated case to the message handling.
* *
* @param type type of message to match * @param type type of message to match
* @param test a predicate that will be evaluated on the argument if the type matches * @param test a predicate that will be evaluated on the argument if the type matches
* @param handler action to apply if the type matches and the predicate returns true * @param handler action to apply if the type matches and the predicate returns true
* @tparam M type of message to match * @tparam M type of message to match
* @return a new behavior builder with the specified handling appended * @return a new behavior builder with the specified handling appended
@ -65,7 +67,7 @@ final class BehaviorBuilder[T] private (messageHandlers: List[Case[T, T]], signa
* Should normally not be used, but when matching on class with generic type * Should normally not be used, but when matching on class with generic type
* argument it can be useful, e.g. <code>List.class</code> and <code>(List&lt;String&gt; list) -> {...}</code> * argument it can be useful, e.g. <code>List.class</code> and <code>(List&lt;String&gt; list) -> {...}</code>
* *
* @param type type of message to match * @param type type of message to match
* @param handler action to apply when the type matches * @param handler action to apply when the type matches
* @return a new behavior builder with the specified handling appended * @return a new behavior builder with the specified handling appended
*/ */
@ -75,7 +77,7 @@ final class BehaviorBuilder[T] private (messageHandlers: List[Case[T, T]], signa
/** /**
* Add a new case to the message handling matching equal messages. * Add a new case to the message handling matching equal messages.
* *
* @param msg the message to compare to * @param msg the message to compare to
* @param handler action to apply when the message matches * @param handler action to apply when the message matches
* @return a new behavior builder with the specified handling appended * @return a new behavior builder with the specified handling appended
*/ */
@ -98,7 +100,7 @@ final class BehaviorBuilder[T] private (messageHandlers: List[Case[T, T]], signa
/** /**
* Add a new case to the signal handling. * Add a new case to the signal handling.
* *
* @param type type of signal to match * @param type type of signal to match
* @param handler action to apply if the type matches * @param handler action to apply if the type matches
* @tparam M type of signal to match * @tparam M type of signal to match
* @return a new behavior builder with the specified handling appended * @return a new behavior builder with the specified handling appended
@ -109,8 +111,8 @@ final class BehaviorBuilder[T] private (messageHandlers: List[Case[T, T]], signa
/** /**
* Add a new predicated case to the signal handling. * Add a new predicated case to the signal handling.
* *
* @param type type of signals to match * @param type type of signals to match
* @param test a predicate that will be evaluated on the argument if the type matches * @param test a predicate that will be evaluated on the argument if the type matches
* @param handler action to apply if the type matches and the predicate returns true * @param handler action to apply if the type matches and the predicate returns true
* @tparam M type of signal to match * @tparam M type of signal to match
* @return a new behavior builder with the specified handling appended * @return a new behavior builder with the specified handling appended
@ -127,7 +129,7 @@ final class BehaviorBuilder[T] private (messageHandlers: List[Case[T, T]], signa
/** /**
* Add a new case to the signal handling matching equal signals. * Add a new case to the signal handling matching equal signals.
* *
* @param signal the signal to compare to * @param signal the signal to compare to
* @param handler action to apply when the message matches * @param handler action to apply when the message matches
* @return a new behavior builder with the specified handling appended * @return a new behavior builder with the specified handling appended
*/ */
@ -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]
if ((cls.isEmpty || cls.get.isAssignableFrom(msg.getClass)) && (predicate.isEmpty || predicate.get.apply(msg))) } else {
handler(msg) val Case(cls, predicate, handler) = handlers(idx)
else receive(msg, tail) if ((cls.isEmpty || cls.get.isAssignableFrom(msg.getClass)) && (predicate.isEmpty || predicate.get.apply(msg)))
case Nil => handler(msg)
else if (idx == handlers.length - 1)
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]
if ((cls.isEmpty || cls.get.isAssignableFrom(msg.getClass)) && (predicate.isEmpty || predicate.get.test(msg))) } else {
handler(msg) val Case(cls, predicate, handler) = handlers(idx)
else receive[M](msg, tail) if ((cls.isEmpty || cls.get.isAssignableFrom(msg.getClass)) && (predicate.isEmpty || predicate.get.test(msg)))
case _ => handler(msg)
Behaviors.unhandled else if (idx == handlers.length - 1)
Behaviors.unhandled[T]
else
receive(msg, handlers, idx + 1)
} }
}
} }