13: 2198998566,646 ops/s
Iteration 14: 2201966804,597 ops/s
Iteration 15: 2215531292,317 ops/s
Iteration 16: 2155095714,297 ops/s
Iteration 17: 2146037784,423 ops/s
Iteration 18: 2139622262,798 ops/s
Iteration 19: 2213499245,208 ops/s
Iteration 20: 2191108429,343 ops/s
向基准中添加SFL4J
前面不是说过吗,我们要测试的用例是日志记录,那么在这个项目中我将使用SFL4J和Logback,我们向pom文件中增加依赖:
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.7</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.0.11</version>
</dependency>
然后我们增加一个logback.xml
配置文件,并设置日志输出级别为INFO
。
<configuration>
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%highlight(%d{HH:mm:ss.SSS} [%thread] %-5level %logger - %msg%n)</pattern>
</encoder>
</appender>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder><pattern>%msg%n</pattern></encoder>
</appender>
<root level="INFO">
<appender-ref ref="CONSOLE" />
</root>
</configuration>
使用maven-shade-plugin的好处是,当我们使用maven对应用进行打包的时候,所有的依赖和配置文件等都会打包到target目录下。
在日志中使用字符串连接
开始第一个微基准测试:在日志中使用字符串连接。这里我们将所需代码写到由@Benchmark
注解标注的方法中,然后其他的事情就交给JMH。
这段代码中,我们创建x,y,z三个字符串变量,然后在循环中,使用字符串连接的形式将调试日志输出。代码如下:
import org.openjdk.jmh.annotations.Benchmark;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class MyBenchmark {
private static final Logger logger = LoggerFactory.getLogger(MyBenchmark.class);
@Benchmark
public void testConcatenatingStrings() {
String x = "", y = "", z = "";
for (int i = 0; i < 100; i++) {
x += i; y += i; z += i;
logger.debug("Concatenating strings " + x + y + z);
}
}
}
然后还是像刚刚一样,运行这个微基准测试,并查看迭代输出。
译者注:后文将统一进行对比。
在日志中使用变量参数
这个微基准测试中,我们使用变量参数来代替字符串连接,更改代码内容如下,然后打包执行。
@Benchmark
public void testVariableArguments() {
String x = "", y = "", z = "";
for (int i = 0; i < 100; i++) {
x += i; y += i; z += i;
logger.debug("Variable arguments {} {} {}", x, y, z);
}
}
在日志中使用If判断语句
最后一个也是最重要的一个,使用日志输出时使用isDebugEnabled()
进行优化
@Benchmark
public void testIfDebugEnabled() {
String x = "", y = "", z = "";
for (int i = 0; i < 100; i++) {
x += i; y += i; z += i;
if (logger.isDebugEnabled())
logger.debug("If debug enabled {} {} {}", x, y, z);
}
}
微基准测试的结果
在运行三个微基准测试之后,我们将预期结果(记住,don’t guess, measure)。每秒的操作次数越多,表示性能越好。如果我们看看下表的最后一行,我们注意到使用isDebugEnabled
的性能最好,使用字符串连接最糟糕。同时也能发现,在没有使用isDebugEnabled
而是使用变量参数的测试结果并不差。 综合代码的可读性(较少的boilerplate code
(模块化代码,也可以理解为不重要,但是又不可缺少的代码)) 。所以我会选择使用变量参数的那种形式!
|
String concatenation |
Variable arguments |
if isDebugEnabled |
Iteration 1 |
57108,635 ops/s |
97921,939 ops/s |
104993,368 ops/s |
Iteration 2 |
58441,293 ops/s |
98036,051 ops/s |
104839,216 ops/s |
Iteration 3 |
58231,243 ops/s |
97457,222 ops/s |
106601 |