介紹
我們?cè)谶x擇不同框架草慧、算法時(shí),不同場(chǎng)景下的性能是很重要考慮因素洽议。JMH這個(gè)Java的微基準(zhǔn)測(cè)試框架提供簡(jiǎn)單的方式來實(shí)現(xiàn)性能測(cè)試的需求。本文將以一個(gè)對(duì)比序列化器性能的例子簡(jiǎn)單介紹JMH的使用一汽。
創(chuàng)建項(xiàng)目
不同于 JUnit
這種測(cè)試框架,JMH推薦創(chuàng)建獨(dú)立的項(xiàng)目來做測(cè)試。
使用maven創(chuàng)建
mvn archetype:generate \
-DinteractiveMode=false \
-DarchetypeGroupId=org.openjdk.jmh \
-DarchetypeArtifactId=jmh-java-benchmark-archetype \
-DgroupId=org.sample \
-DartifactId=test \
-Dversion=1.0
執(zhí)行命令后生成項(xiàng)目
IDEA中創(chuàng)建項(xiàng)目
除了maven命令直接創(chuàng)建之外召夹,也可以選擇在IDE中創(chuàng)建maven岩喷,以IDEA為例。
在創(chuàng)建項(xiàng)目時(shí)监憎,選擇Maven項(xiàng)目纱意,勾選 Create from archetype
并選擇 Add Archetype...
在彈出的窗口中填入對(duì)應(yīng)信息(當(dāng)前最新版本為1.33)
之后就可以選擇JMH的archetype在IDEA中創(chuàng)建項(xiàng)目了。
編寫測(cè)試代碼
項(xiàng)目自動(dòng)生成的 pom.xml
文件中已經(jīng)包含JMH運(yùn)行最小依賴了鲸阔,只需要加上待測(cè)試相關(guān)的依賴包偷霉。這里我要測(cè)試的是 spring-data-redis
中序列化對(duì)象相關(guān)的內(nèi)容,因此需要添加以下依賴:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<version>2.1.1.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.12.3</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.12.3</version>
</dependency>
之后編寫測(cè)試代碼褐筛,這里我使用了對(duì)比了 ObjectHashMapper
和 Jackson2HashMapper
兩個(gè)類的 toHash
方法平均調(diào)用時(shí)間类少。預(yù)熱5輪硫狞,實(shí)際測(cè)試5輪并fork 5 個(gè)進(jìn)程來進(jìn)行測(cè)試妓忍。
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@Warmup(iterations = 5, time = 1)
@Measurement(iterations = 5, time = 1)
@Fork(5)
@State(Scope.Benchmark)
public class MyBenchmark {
private HashMapper objectHashMapper;
private HashMapper jacksonHashMapper;
@Setup
public void setup() {
objectHashMapper = new ObjectHashMapper();
jacksonHashMapper = new Jackson2HashMapper(false);
}
@Benchmark
public void testObjectHashMapper() {
SesAnswerRate answerRatePredictor = new SesAnswerRate(0.3F, 0.5F);
objectHashMapper.toHash(answerRatePredictor);
}
@Benchmark
public void testJacksonHashMapper() {
SesAnswerRate answerRatePredictor = new SesAnswerRate(0.3F, 0.5F);
jacksonHashMapper.toHash(answerRatePredictor);
}
public static void main(String[] args) throws RunnerException {
Options options = new OptionsBuilder()
.include(MyBenchmark.class.getSimpleName())
.build();
new Runner(options).run();
}
}
建議IDEA用戶安裝idea-jmh-plugin插件定罢,便于運(yùn)行測(cè)試。
執(zhí)行測(cè)試
如果沒有安裝IDE插件琼蚯,可以執(zhí)行 mvn clean package
打包惠况,之后在項(xiàng)目下的target文件夾中執(zhí)行 java -jar benchmarks.jar
運(yùn)行。
最終運(yùn)行結(jié)果如下:
Benchmark Mode Cnt Score Error Units
MyBenchmark.testJacksonHashMapper avgt 25 536.386 ± 25.589 ns/op
MyBenchmark.testObjectHashMapper avgt 25 1601.561 ± 139.910 ns/op
可以看到使用 Jackson2HashMapper
序列化對(duì)象的速度要比 ObjectHashMapper
快上3倍峦睡。
總結(jié)
可以看到利用JMH能夠快速編寫,運(yùn)行測(cè)試代碼龙屉,對(duì)于method級(jí)別的性能測(cè)試非常有用转捕,篇幅所限在此不展開講述更加具體的用法瓜富。
建議有需要的同學(xué)們閱讀官方示例: jmh-samples