简体   繁体   English

scala日志库中的性能按值调用vs按名称调用

[英]performance in scala logging libraries call-by-value vs call-by-name

I've been looking at the various scala logging libraries lately, and the vast majority of them implement their logging functions as 我最近一直在关注各种scala日志库,其中绝大多数都实现了日志记录功能

def debug(s: => String)

So that if you have debug logging turned off, it won't execute the statement. 因此,如果关闭调试日志记录,它将不会执行该语句。 However, I just came across logula which specifically states as one of its benefits 但是,我刚刚遇到了logula ,它特别指出了它的一个好处

Unlike a lot of Scala logging libraries, Logula doesn't use pass-by-name semantics (eg, f: => A) for its logging statements, which means two things: 与许多Scala日志库不同,Logula不会对其日志记录语句使用按名称传递语义(例如,f:=> A),这意味着两件事:

  • The Scala compiler doesn't have to create one-off closure objects for each logging statement. Scala编译器不必为每个日志记录语句创建一次性闭包对象。 This should reduce the amount of garbage collection pressure. 这应该减少垃圾收集压力。

Which actually makes total sense to me. 这实际上对我来说是完全合理的。 So my question is, is there any real world performance benchmarks/data comparing the 2 approaches? 所以我的问题是,是否存在比较这两种方法的真实世界性能基准/数据? Ideally something from a live project versus contrived benchmarks? 理想情况下,从现场项目到人为的基准测试?

Which is faster depends entirely upon use cases. 哪个更快取决于用例。 If you are logging static strings, then it's faster to just pass that constant string in and ignore it. 如果您正在记录静态字符串,那么只需传递该常量字符串并忽略它就会更快。 Otherwise, if you're creating strings you have to create at least one object anyway. 否则,如果您正在创建字符串,则无论如何都必须创建至少一个对象。 Function objects are tiny and cheap--you're better off creating one of those than the string if you're going to ignore it. 函数对象很小且很便宜 - 如果你要忽略它,你最好创建其中一个而不是字符串。

Personally, I think this sort of first-principles understanding of the tradeoffs is even more valuable than a case study of a particular application that may have used one or the other, because it lets you understand why you would choose one or the other (and you'll still always want to benchmark your own application). 就个人而言,我认为这种对权衡的第一原则理解甚至比对某个特定应用的案例研究更有价值,因为它可以让你理解为什么你会选择其中一个(和你仍然总是希望对自己的应用程序进行基准测试。

(Note: how expensive object creation is depends on how heavily impacted the garbage collector is; generally, short-lived objects can be created and disposed of at a rate of on the order of 10 8 per second, which shouldn't be a concern except in tight inner loops. If you're putting logging statements in tight inner loops, I think something is wrong. You should be writing unit tests for that instead.) (注意:对象创建的成本有多大取决于垃圾收集器的影响程度;通常,可以以每秒10 8的速率创建和处理短期对象,这不应该是一个问题除了在紧密的内部循环中。如果你将日志语句放在紧密的内部循环中,我认为有些错误。你应该为此编写单元测试。)

I'll go out on a limb and say that philosophical discussions about tradeoffs are more useful when there is some interesting tradeoff to be made, which is to say, not here. 我会滔滔不绝地说,当有一些有趣的权衡要做时,关于权衡的哲学讨论会更有用,也就是说,不是在这里。

class A {
  var debugging = true
  @inline final def debug(msg: => String) = if (debugging) println(msg)

  def f = { debug("I'm debugging!") ; 5 }
}
% scalac292 -optimise a.scala
% ls -l *.class
-rw-r--r--  1 paulp  staff  1503 Jul 31 22:40 A.class
%

Count the closure objects. 计算闭包对象。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM