代码之家  ›  专栏  ›  技术社区  ›  ninja.coder

Log4j中的字符串串联性能

  •  7
  • ninja.coder  · 技术社区  · 6 年前

    我经常听到人们说,这是最好避免的做法之一 String Concatenation 和使用 {} 而是在日志记录时。

    我在调查 Log4j 编写代码以查看他们是如何处理此问题的,并认为他们正在做类似的事情。

    以下是 format() 方法,它接受模式和参数并返回要记录的消息。

    /**
     * Formats arguments using SLF4J-like formatter.
     * @param pattern pattern, may be malformed.
     * @param arguments arguments.
     * @return Message string
     */
    private static String format(final String pattern,
                                 final Object[] arguments) {
        if (pattern != null) {
            String retval = "";
            int count = 0;
            int prev = 0;
            int pos = pattern.indexOf("{");
            while(pos >= 0) {
                if (pos == 0 || pattern.charAt(pos-1) != '\\') {
                    retval += pattern.substring(prev, pos);
                    if (pos + 1 < pattern.length() && pattern.charAt(pos+1) == '}') {
                        if(arguments != null && count < arguments.length) {
                            retval += arguments[count++];
                        } else {
                            retval += "{}";
                        }
                        prev = pos + 2;
                    } else {
                        retval += "{";
                        prev = pos + 1;
                    }
                } else {
                    retval += pattern.substring(prev, pos - 1) + "{";
                    prev = pos + 1;
                }
                pos = pattern.indexOf("{", prev);
            }
            return retval + pattern.substring(prev);
        }
        return null;
    }
    

    我无法理解这种实现如何比使用串联更好。对此的任何见解都将非常有用。

    3 回复  |  直到 6 年前
        1
  •  12
  •   larsgrefer    6 年前

    在日志系统中设置字符串格式的好处是,日志系统可以决定是否必须进行字符串串联。

    让我们以这些行为例:

    log.debug("Count: " + list.size());
    log.debug("Count: {}", list.size());
    

    只要此记录器的级别为debug或更低,性能就没有差别,但如果日志级别高于debug,则第二行根本不会执行串联。

        2
  •  7
  •   Stephen C    3 年前

    这个问题的一些答案解释如下:

    短版本是基于格式的使用速度更快,因为

       Logger.debug("my name is {}", name);
    

    只会发生昂贵的字符串碰撞 之后 log4j决定需要记录事件;e、 g.根据记录级别等进行过滤后。

    相比之下,字符串串联版本

       Logger.debug("my name is " + name);
    

    计算参数时会发生字符串碰撞。因此,即使在没有实际记录事件的情况下也会发生这种情况。您可以通过在代码中添加“警卫”来部分避免这种情况(见下文),但这样做会使应用程序记录调用变得冗长。


    但看看这个例子:

       log.debug("Count: " + list.size());
       log.debug("Count: {}", list.size());
    

    格式版本会更快,但两个版本 总是 评估 list.size() 表示如果这是一项昂贵的操作,那么您可能需要使用防护装置;e、 g。

       if (log.isDebugEnabled()) {
           log.debug("Count: " + list.size());
       }
    
        3
  •  0
  •   Mehmet Akbilgin    3 年前

    不执行列表的备选方案。大小():

    // Instead of
    if (log.isDebugEnabled()) {
       log.debug("Count: " + list.size());
    }
    
    // Use if >= Java 8
    log.debug("Count: {}", () -> list.size());
    

    这将评估列表。仅在需要时使用size()。

    信用证: https://garygregory.wordpress.com/2015/09/16/a-gentle-introduction-to-the-log4j-api-and-lambda-basics/