Java Language
Benchmarks
Suche…
Einführung
Das Schreiben von Leistungsbenchmarks in Java ist nicht so einfach wie das System.currentTimeMillis()
am Anfang und am Ende und Berechnen der Differenz. Um gültige Leistungsbenchmarks zu schreiben, sollte man geeignete Werkzeuge verwenden.
Einfaches JMH-Beispiel
Eines der Tools zum Schreiben richtiger Benchmark-Tests ist JMH . HashSet
, wir möchten die Leistung eines HashSet
in HashSet
und TreeSet
.
Der einfachste Weg, um JHM in Ihr Projekt zu integrieren - besteht darin, das Plug-in für Maven und Schatten zu verwenden . Sie können auch pom.xml
aus JHM-Beispielen sehen .
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.0.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<finalName>/benchmarks</finalName>
<transformers>
<transformer
implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>org.openjdk.jmh.Main</mainClass>
</transformer>
</transformers>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-core</artifactId>
<version>1.18</version>
</dependency>
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-generator-annprocess</artifactId>
<version>1.18</version>
</dependency>
</dependencies>
Danach müssen Sie die Benchmark-Klasse selbst schreiben:
package benchmark;
import org.openjdk.jmh.annotations.*;
import org.openjdk.jmh.infra.Blackhole;
import java.util.HashSet;
import java.util.Random;
import java.util.Set;
import java.util.TreeSet;
import java.util.concurrent.TimeUnit;
@State(Scope.Thread)
public class CollectionFinderBenchmarkTest {
private static final int SET_SIZE = 10000;
private Set<String> hashSet;
private Set<String> treeSet;
private String stringToFind = "8888";
@Setup
public void setupCollections() {
hashSet = new HashSet<>(SET_SIZE);
treeSet = new TreeSet<>();
for (int i = 0; i < SET_SIZE; i++) {
final String value = String.valueOf(i);
hashSet.add(value);
treeSet.add(value);
}
stringToFind = String.valueOf(new Random().nextInt(SET_SIZE));
}
@Benchmark
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public void testHashSet(Blackhole blackhole) {
blackhole.consume(hashSet.contains(stringToFind));
}
@Benchmark
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
public void testTreeSet(Blackhole blackhole) {
blackhole.consume(treeSet.contains(stringToFind));
}
}
Bitte beachte dieses blackhole.consume()
, wir werden später darauf zurückkommen. Wir brauchen auch die Hauptklasse für das Laufen von Benchmark:
package benchmark;
import org.openjdk.jmh.runner.Runner;
import org.openjdk.jmh.runner.RunnerException;
import org.openjdk.jmh.runner.options.Options;
import org.openjdk.jmh.runner.options.OptionsBuilder;
public class BenchmarkMain {
public static void main(String[] args) throws RunnerException {
final Options options = new OptionsBuilder()
.include(CollectionFinderBenchmarkTest.class.getSimpleName())
.forks(1)
.build();
new Runner(options).run();
}
}
Und wir sind fertig. Wir müssen nur das mvn package
ausführen (es erstellt benchmarks.jar
in Ihrem /target
Ordner) und führen unseren Benchmark-Test aus:
java -cp target/benchmarks.jar benchmark.BenchmarkMain
Und nach einigen Aufwärm- und Berechnungs-Iterationen haben wir unsere Ergebnisse:
# Run complete. Total time: 00:01:21
Benchmark Mode Cnt Score Error Units
CollectionFinderBenchmarkTest.testHashSet avgt 20 9.940 ± 0.270 ns/op
CollectionFinderBenchmarkTest.testTreeSet avgt 20 98.858 ± 13.743 ns/op
Über dieses blackhole.consume()
. Wenn Ihre Berechnungen den Status Ihrer Anwendung nicht ändern, wird Java ihn höchstwahrscheinlich einfach ignorieren. Um dies zu vermeiden, können Sie Ihre Benchmark-Methoden entweder dazu bringen, einen bestimmten Wert zurückzugeben, oder das Objekt mit dem Blackhole
Objekt verbrauchen.
Weitere Informationen zum Schreiben der richtigen Benchmarks finden Sie im Blog von Aleksey Shipilëv, im Blog von Jacob Jenkov und im Java-Performance-Blog: 1 , 2 .