Начиная с JDK-12 , JDK поставляется с JMH (Java Microbenchmark Harness). Это инструментарий, который помогает правильно реализовывать Java-микробенчмарки. JMH разрабатывается теми же людьми, которые внедряют виртуальную машину Java (JVM), чтобы они знали внутреннее устройство и то, как Java выполняет оптимизацию во время выполнения.
Вам также может понравиться:
JMH: Benchmark REST API
Почему JMH?
Существует множество оптимизаций, которые JVM или базовое оборудование могут применить к вашему компоненту, когда тест производительности выполняет этот компонент изолированно. Эти оптимизации не могут быть применимы, когда компонент работает как часть более крупного приложения. Таким образом, неправильно внедренные микробенчмарки могут заставить вас поверить, что производительность вашего компонента лучше, чем будет на самом деле.
Всякий раз, когда мы сталкиваемся с проблемой, мы склонны решать ее рекурсивно, итеративно или с помощью встроенных методов, предоставляемых на нашем языке. После кодирования мы склонны путать, что для данного набора данных (больших, маленьких, фиксированных) у меня будет лучшее преимущество — использовать встроенные методы или метод 1 или метод 2 или … метод 3 .
В этой статье я буду ссылаться на метод как на отдельный компонент , так как моя задача — показать вам, как тестировать ваши методы с использованием JMH в соответствии с их производительностью.
Перед началом работы необходимо выполнить несколько предварительных условий. Если у вас нет JDK 12, вам нужно импортировать зависимости в свой проект, для чего вы можете загрузить JAR-файлы для создания проекта maven и добавить следующие зависимости:
Джава
1
<dependencies>
2
<dependency>
3
<artifactId>jmh-core</artifactId>
4
<groupId>org.openjdk.jmh</groupId>
5
<version>${jmh.version}</version>
6
</dependency>
7
<dependency>
8
<artifactId>jmh-generator-annprocess</artifactId>
9
<groupId>org.openjdk.jmh</groupId>
10
<version>${jmh.version}</version>
11
</dependency>
12
</dependencies>
13
<p>
14
<jmh.version>1.21</jmh.version>
15
</properties>
Для простоты, давайте возьмем пример для генерации N натуральных чисел и сохранения их в List
.
List<Integer> list
помощью list.add()
.stream
чтобы сгенерировать Intstream
от 1 до N, а затем сохранить, чем до list
.Джава
xxxxxxxxxx
1
import java.util.ArrayList;
2
import java.util.List;
3
import java.util.stream.Collectors;
4
import java.util.stream.IntStream;
5
import org.openjdk.jmh.annotations.Benchmark;
6
import org.openjdk.jmh.annotations.BenchmarkMode;
7
import org.openjdk.jmh.annotations.Mode;
8
import org.openjdk.jmh.annotations.Param;
9
import org.openjdk.jmh.annotations.Scope;
10
import org.openjdk.jmh.annotations.State;
11
import org.openjdk.jmh.runner.Runner;
12
import org.openjdk.jmh.runner.RunnerException;
13
import org.openjdk.jmh.runner.options.Options;
14
import org.openjdk.jmh.runner.options.OptionsBuilder;
15
Scope.Thread) (
17
public class Testing {
18
"10"}) ({
20
private int number;
21
23
Mode.All}) ({
24
//traditional method to generate N numbers and store it in List
25
public List<Integer> traditionalMethod(Testing T) {
26
List<Integer> list = new ArrayList<>();
27
for (int i = 1; i <= number; i++) {
28
list.add(i);
29
}
30
return list;
31
}
32
34
Mode.All}) ({
35
//using #stream to generate N numbers and store it in List
36
public List<Integer> streamMethod(Testing T) {
37
return IntStream.rangeClosed(1, number).boxed().collect(Collectors.toList());
38
}
39
public static void main(String[] args) throws RunnerException {
41
Options opt = new OptionsBuilder()
42
.include(Testing.class.getSimpleName())
43
.forks(1)
44
.build();
45
new Runner(opt).run();
47
}
48
}
49
После запуска программы результаты выглядят следующим образом:
Пропускная способность потокового метода лучше для небольшого диапазона 10, она может или не может быть одинаковой для большего набора данных.
Подробный проект был загружен на GitHub, вы можете его разветвить и запустить в своей локальной среде, а также можете изменить или добавить свои собственные методы и проверить, как они работают с точки зрения производительности.
Следующая статья, @BenchmarkMode({Mode.All})
которая будет тестировать все следующее:
Throughput("thrpt", "Throughput, ops/time"),
AverageTime("avgt", "Average time, time/op"),
SampleTime("sample", "Sampling time"),
SingleShotTime("ss", "Single shot invocation time"),
All("all", "All benchmark modes");
Если вам нужно измерить только пропускную способность, используйте Mode.Throughput
.
Дальнейшее чтение
Тестирование производительности JMH InfinityDB