性能测试中的第一个循环较慢
First loop slower in performance test
我想亲眼看看某些数据结构的行为方式。我从 ArrayList
开始,并用自定义 class 的对象填充它。但是当我玩弄它时,我注意到 运行ning 测试方法 X 在上面它的执行速度要慢得多,或者如果我第二次做同样的工作两次,速度最多快 6 倍。
这里有一些例子:
private void generateItems(int amount)
{
System.out.println("Populating list with " + amount + " items...");
long time = System.nanoTime();
for (int i = 0; i < amount; i++)
{
items.add(new Item("Type", "Subtype", random.nextInt(width), random.nextInt(height)));
}
System.out.println(timePassed(time) + " List size: " + items.size());
}
private void sortList(int x, int y)
{
System.out.println("Sorting list...");
long time = System.nanoTime();
Collections.sort(items, new ItemComparator(x, y));
System.out.println(timePassed(time) + " List sorted.");
System.out.println("First: " + items.get(0));
}
现在让我们运行这两个方法两次:
items = new ArrayList<>();
generateItems(100000); //33ms
sortList(0, 0); //118ms
items = new ArrayList<Item>();
generateItems(100000); //5ms
sortList(0, 0); //28ms
我知道当我对一个已经排序的列表进行排序时会花费更少的时间,因为计算机会更好地赌博结果,但在这里我生成了两个完全随机的列表。
我还有一些涉及迭代和条件项检索的方法,它们的行为都相同:第一个比 运行 以后要慢得多。
为了继续对其他数据结构进行测试,我想了解更多关于此行为的信息。也许我在这里做错了什么或者结果是预期的,为什么?我如何进行这些比较可靠的测试?
Perhaps I'm doing something wrong here or is the outcome expected and why?
是的,Java 是默认带有 JIT 的 JVM。这意味着代码是动态编译的,因为它是 运行。因此,开始时 运行 速度较慢,但随着它获得有关程序如何运行的更好采样数据而加快速度 运行。
您可以在命令行中使用-XX:+PrintCompilation
查看一些细节。注意一些方法会被多次编译,有时编译优化成本更高,有时因为它有更好的数据来优化代码。
How do I make somewhat reliable tests like these?
简单的答案是 运行 重复测试并至少忽略基准测试的前 2 秒。
要获得更好的答案,请使用 JMH。默认情况下,这将 运行 每个测试 10 秒,超过 20 次,并在 运行 进行实际测试和编写微基准测试的许多更好方法之前忽略此预热。
How do I make somewhat reliable tests like these?
不要使用手动基准测试,使用 OpenJdk/jmh:
class MyTest {
@Benchmark
private void generateItemsTest() {
generateItems(100000);
}
@Benchmark
private void sortListTest() {
generateItems(100000);
sort(0, 0)
}
public static void main(String[] args) throws RunnerException {
Options opt = new OptionsBuilder()
.include(MyTest.class.getSimpleName())
.forks(1)
.build();
new Runner(opt).run();
}
在 Maven 的 pom.xml 中你应该添加
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-core</artifactId>
<version>1.11.2</version>
</dependency>
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-generator-annprocess</artifactId>
<version>1.11.2</version>
</dependency>
或以其他方式在您的项目中安装 JMH
我想亲眼看看某些数据结构的行为方式。我从 ArrayList
开始,并用自定义 class 的对象填充它。但是当我玩弄它时,我注意到 运行ning 测试方法 X 在上面它的执行速度要慢得多,或者如果我第二次做同样的工作两次,速度最多快 6 倍。
这里有一些例子:
private void generateItems(int amount)
{
System.out.println("Populating list with " + amount + " items...");
long time = System.nanoTime();
for (int i = 0; i < amount; i++)
{
items.add(new Item("Type", "Subtype", random.nextInt(width), random.nextInt(height)));
}
System.out.println(timePassed(time) + " List size: " + items.size());
}
private void sortList(int x, int y)
{
System.out.println("Sorting list...");
long time = System.nanoTime();
Collections.sort(items, new ItemComparator(x, y));
System.out.println(timePassed(time) + " List sorted.");
System.out.println("First: " + items.get(0));
}
现在让我们运行这两个方法两次:
items = new ArrayList<>();
generateItems(100000); //33ms
sortList(0, 0); //118ms
items = new ArrayList<Item>();
generateItems(100000); //5ms
sortList(0, 0); //28ms
我知道当我对一个已经排序的列表进行排序时会花费更少的时间,因为计算机会更好地赌博结果,但在这里我生成了两个完全随机的列表。
我还有一些涉及迭代和条件项检索的方法,它们的行为都相同:第一个比 运行 以后要慢得多。
为了继续对其他数据结构进行测试,我想了解更多关于此行为的信息。也许我在这里做错了什么或者结果是预期的,为什么?我如何进行这些比较可靠的测试?
Perhaps I'm doing something wrong here or is the outcome expected and why?
是的,Java 是默认带有 JIT 的 JVM。这意味着代码是动态编译的,因为它是 运行。因此,开始时 运行 速度较慢,但随着它获得有关程序如何运行的更好采样数据而加快速度 运行。
您可以在命令行中使用-XX:+PrintCompilation
查看一些细节。注意一些方法会被多次编译,有时编译优化成本更高,有时因为它有更好的数据来优化代码。
How do I make somewhat reliable tests like these?
简单的答案是 运行 重复测试并至少忽略基准测试的前 2 秒。
要获得更好的答案,请使用 JMH。默认情况下,这将 运行 每个测试 10 秒,超过 20 次,并在 运行 进行实际测试和编写微基准测试的许多更好方法之前忽略此预热。
How do I make somewhat reliable tests like these?
不要使用手动基准测试,使用 OpenJdk/jmh:
class MyTest {
@Benchmark
private void generateItemsTest() {
generateItems(100000);
}
@Benchmark
private void sortListTest() {
generateItems(100000);
sort(0, 0)
}
public static void main(String[] args) throws RunnerException {
Options opt = new OptionsBuilder()
.include(MyTest.class.getSimpleName())
.forks(1)
.build();
new Runner(opt).run();
}
在 Maven 的 pom.xml 中你应该添加
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-core</artifactId>
<version>1.11.2</version>
</dependency>
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-generator-annprocess</artifactId>
<version>1.11.2</version>
</dependency>
或以其他方式在您的项目中安装 JMH