=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
*/
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.
@ -157,6 +159,7 @@ object BehaviorBuilder {
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
/** INTERNAL API */
@InternalApi
private[javadsl] final case class Case[BT, MT](
@ -177,23 +180,25 @@ object BehaviorBuilder {
* INTERNAL API
*/
@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] {
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] =
receive(msg, signalHandlers)
override def receiveSignal(ctx: TypedActorContext[T], msg: Signal): Behavior[T] = receive(msg, signalHandlers, 0)
@tailrec
private def receive[M](msg: M, handlers: List[Case[T, M]]): Behavior[T] =
handlers match {
case Case(cls, predicate, handler) :: tail =>
private def receive[M](msg: M, handlers: Array[Case[T, M]], idx: Int): Behavior[T] = {
if (handlers.length == 0) {
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)))
handler(msg)
else receive(msg, tail)
case Nil =>
else if (idx == handlers.length - 1)
Behaviors.unhandled[T]
else
receive(msg, handlers, idx + 1)
}
}
}

View file

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