13

我创建了名为 LogActor 的 akka 演员。LogActor 的接收方法处理来自其他参与者的消息并将它们记录到指定的日志级别。

我可以通过两种方式区分不同的级别。第一个:

import LogLevel._
object LogLevel extends Enumeration {
    type LogLevel = Value
    val Error, Warning, Info, Debug = Value
}
case class LogMessage(level : LogLevel, msg : String) 

第二个:(编辑

abstract class LogMessage(msg : String)
case class LogMessageError(msg : String) extends LogMessage(msg)
case class LogMessageWarning(msg : String) extends LogMessage(msg)
case class LogMessageInfo(msg : String) extends LogMessage(msg)
case class LogMessageDebug(msg : String) extends LogMessage(msg)

哪种方式更有效?匹配案例类或匹配枚举值是否需要更少的时间?

(我读了这个问题,但没有任何关于运行时问题的答案)

4

3 回答 3

27

我完全同意 Alexey 和 Dennis 的观点,即这种情况下的性能不应该打扰您,因为这更多是编译器优化的问题,而不是开发人员,而且我无法想象性能差异会变得明显的场景。

应该困扰您的是您的代码一致性,从这个意义上说,您应该根据您的决定是要坚持使用第一个示例中正确描述的枚举的旧 java-ish 方法,还是最近流行的代数数据类型(ADT) 模式。后者你试图在你的第二个例子中表示,但有一些错误。

以下是如何使用 ADT 模式正确解决问题。

ADT 解决方案 #1

// 1. marked `sealed` to make pattern matching exhaustive
// 2. used a trait to avoid double storage of msg` and 
//    make the inheritance easier
sealed trait LogMessage { def msg : String }
// A better solution for isolation than names like "LogMessageError".
// Allows you to either address the members with a namespace like 
// "LogMessage.Error" or do "import LogMessage._" and address them 
// directly
object LogMessage { 
  case class Error (msg : String) extends LogMessage
  case class Warning (msg : String) extends LogMessage
  case class Info (msg : String) extends LogMessage
  case class Debug (msg : String) extends LogMessage
}

ADT 解决方案 #2

很抱歉可能弄乱了你的脑袋,但值得注意的是,对于类似的情况,还有一种替代的 ADT 方法,这有点类似于你使用枚举的方法。

sealed trait LogLevel 
object LogLevel {
  case object Error extends LogLevel
  case object Warning extends LogLevel
  case object Info extends LogLevel
  case object Debug extends LogLevel
}
case class LogMessage ( level : LogLevel, msg : String )
于 2012-11-12T16:50:21.397 回答
8

“不要过早优化”适用。与您将消息传递给您的演员或实际记录它们所花费的时间相比,我认为它们之间的差异根本不重要。但我希望最好的性能是创建一个 Java enum(可以从 Scala 轻松访问和使用)来代替 Scala 来记录日志级别Enumeration

于 2012-11-12T13:29:56.690 回答
0

记录器最常见的操作之一是将当前记录级别与消息级别进行比较,使用枚举可以免费获得它,而使用案例类的设置会有些麻烦。我同意@AlexeyRomanov:匹配不应该是这里的瓶颈。

编辑:性能方面,与案例类匹配将在字节码中使用 instanceof,而对于枚举,scala 编译器生成的代码是我尝试过的任何反编译器都无法处理的。它似乎正在使用equals. 因此,从技术上讲,枚举可能会更快,但实际上在性能上不会有任何差异。

于 2012-11-12T13:45:04.523 回答