在Scala中调试日志,不会影响性能

tel*_*zes 6 debugging optimization logging preprocessor scala

在像C/C++/Objective-C这样的语言中,通常使用预处理器宏来定义甚至不为已发布的二进制文件编译的日志记录机制,从而不会导致性能损失.有点像:

#ifdef DEBUG
printf("some event we want to log\n");
#endif
Run Code Online (Sandbox Code Playgroud)

现在,我知道Scala中没有预处理器.所以我的问题是:为了调试目的,实现记录程序活动的机制的最佳方法是什么,而在关闭时影响性能最少?

sen*_*nia 15

您可以使用 scala.annotation.elidable

可以在生成的代码中删除调用的方法的注释.

行为受到-xelide-below to scalac的影响.如果给定注释的优先级低于命令行参数,则生成的代码中将省略标记为elidable的方法.例子:


axe*_*l22 5

当前的做法(在Scala 2.9.x或更早版本中)是使用thunk类型(例如,参见Scala SLFS的简单日志外观):

def log(x: =>Any) = if (logging) println(x)

// later in code
log("var1: " + myVar1)
Run Code Online (Sandbox Code Playgroud)

这通常比实际构造字符串便宜,因为字符串创建(以及任何后续活动)仅在if logging为true时才会完成.但是,它仍然会导致x上面的thunk创建闭包的成本.

但是,从Scala 2.10.x开始,标准发行版中包含一个实验性宏实现(请参阅本页SIP).宏系统将允许您编写几乎没有运行时成本的日志记录调用(除了logging变量检查) - 它们允许您内联调用log,以便:

log("var1: " + myVar1)
Run Code Online (Sandbox Code Playgroud)

变为:

if (logging) log("var1: " + myVar1)
Run Code Online (Sandbox Code Playgroud)

请注意,在这种情况下,没有为其创建闭包log,并且仅在if logging为true 时才评估日志记录消息字符串- 成本仅为if-check.

  • 如果这些设置告诉完全省略日志,宏也可以内省编译器设置并发出空树. (5认同)