你现在使用的性能测试方法并不可靠,手动编写微基准测试通常也不是一个好主意。例如,在编译代码时,JVM 可能会选择更改执行顺序,并且开始和停止变量可能没有被分配到您期望它们被分配的位置,从而导致测量结果出现意外的结果。同样非常重要的是要预热 JVM,让 JIT 编译器进行所有优化。垃圾回收(GC)也可以在引入应用程序吞吐量和响应时间变化方面发挥非常重要的作用。我强烈建议使用专业工具,如 JMH 和 Caliper 进行微基准测试。
我还编写了一些带有 JVM 预热、随机数据集和更高迭代次数的基准测试代码。结果表明,Java 8 流提供了更好的结果。
public class MatrixMultiplicationBenchmark {
private static AtomicLong start = new AtomicLong();
private static AtomicLong stop = new AtomicLong();
private static Random random = new Random();
public static void main(String[] args) {
System.out.println("Warming up...");
IntStream.range(0, 10_000_000).forEach(i -> run(10, MatrixMultiplicationBenchmark::multiplyWithStreams));
IntStream.range(0, 10_000_000).forEach(i -> run(10, MatrixMultiplicationBenchmark::multiplyWithForLoops));
startWatch("Running MatrixMultiplicationBenchmark::multiplyWithForLoops...");
IntStream.range(0, 10).forEach(i -> run(10_000_000, MatrixMultiplicationBenchmark::multiplyWithForLoops));
endWatch("MatrixMultiplicationBenchmark::multiplyWithForLoops");
startWatch("Running MatrixMultiplicationBenchmark::multiplyWithStreams...");
IntStream.range(0, 10).forEach(i -> run(10_000_000, MatrixMultiplicationBenchmark::multiplyWithStreams));
endWatch("MatrixMultiplicationBenchmark::multiplyWithStreams");
}
public static void run(int size, BiFunction<double[][], double[], double[]> multiplyImpl) {
double[][] matrix = new double[size][10];
double[] vector = random.doubles(10, 0.0, 10.0).toArray();
IntStream.range(0, size).forEach(i -> matrix[i] = random.doubles(10, 0.0, 10.0).toArray());
double[] result = multiplyImpl.apply(matrix, vector);
}
public static double[] multiplyWithStreams(final double[][] matrix, final double[] vector) {
final int rows = matrix.length;
final int columns = matrix[0].length;
return IntStream.range(0, rows)
.mapToDouble(row -> IntStream.range(0, columns)
.mapToDouble(col -> matrix[row][col] * vector[col])
.sum()).toArray();
}
public static double[] multiplyWithForLoops(double[][] matrix, double[] vector) {
int rows = matrix.length;
int columns = matrix[0].length;
double[] result = new double[rows];
for (int row = 0; row < rows; row++) {
double sum = 0;
for (int column = 0; column < columns; column++) {
sum += matrix[row][column] * vector[column];
}
result[row] = sum;
}
return result;
}
private static void startWatch(String label) {
System.out.println(label);
start.set(System.currentTimeMillis());
}
private static void endWatch(String label) {
stop.set(System.currentTimeMillis());
System.out.println(label + " took " + ((stop.longValue() - start.longValue()) / 1000) + "s");
}
}
这里是输出结果
Warming up...
Running MatrixMultiplicationBenchmark::multiplyWithForLoops...
MatrixMultiplicationBenchmark::multiplyWithForLoops took 100s
Running MatrixMultiplicationBenchmark::multiplyWithStreams...
MatrixMultiplicationBenchmark::multiplyWithStreams took 89s