gpt4 book ai didi

java - 为什么减少循环次数并不能加快程序速度?

转载 作者:搜寻专家 更新时间:2023-10-31 20:26:18 25 4
gpt4 key购买 nike

我有一个程序可以进行大量的矩阵乘法运算。我想我会通过减少代码中的循环次数来加快它的速度,看看它会快多少(我稍后会尝试矩阵数学库)。事实证明它一点也不快。我已经能够使用一些示例代码重现该问题。我的猜测是 testOne() 会比 testTwo() 快,因为它不创建任何新数组,而且它有三分之一的循环。在我的机器上,它的运行时间是原来的两倍:

Duration for testOne with 5000 epochs: 657, loopCount: 64000000

Duration for testTwo with 5000 epochs: 365, loopCount: 192000000

我的猜测是 multOne()multTwo() 慢,因为在 multOne() 中 CPU 没有写入顺序内存地址就像它在 multTwo() 中一样。听起来对吗?任何解释将不胜感激。

import java.util.Random;

public class ArrayTest {

double[] arrayOne;
double[] arrayTwo;
double[] arrayThree;

double[][] matrix;

double[] input;
int loopCount;

int rows;
int columns;

public ArrayTest(int rows, int columns) {
this.rows = rows;
this.columns = columns;
this.loopCount = 0;
arrayOne = new double[rows];
arrayTwo = new double[rows];
arrayThree = new double[rows];
matrix = new double[rows][columns];
Random random = new Random();
for (int i = 0; i < rows; i++) {
for (int j = 0; j < columns; j++) {
matrix[i][j] = random.nextDouble();
}
}
}

public void testOne(double[] input, int epochs) {
this.input = input;
this.loopCount = 0;
long start = System.currentTimeMillis();
long duration;
for (int i = 0; i < epochs; i++) {
multOne();
}
duration = System.currentTimeMillis() - start;
System.out.println("Duration for testOne with " + epochs + " epochs: " + duration + ", loopCount: " + loopCount);
}

public void multOne() {
for (int i = 0; i < rows; i++) {
for (int j = 0; j < columns; j++) {
arrayOne[i] += matrix[i][j] * arrayOne[i] * input[j];
arrayTwo[i] += matrix[i][j] * arrayTwo[i] * input[j];
arrayThree[i] += matrix[i][j] * arrayThree[i] * input[j];
loopCount++;
}
}
}

public void testTwo(double[] input, int epochs) {

this.loopCount = 0;
long start = System.currentTimeMillis();
long duration;
for (int i = 0; i < epochs; i++) {
arrayOne = multTwo(matrix, arrayOne, input);
arrayTwo = multTwo(matrix, arrayTwo, input);
arrayThree = multTwo(matrix, arrayThree, input);
}
duration = System.currentTimeMillis() - start;
System.out.println("Duration for testTwo with " + epochs + " epochs: " + duration + ", loopCount: " + loopCount);
}

public double[] multTwo(double[][] matrix, double[] array, double[] input) {
double[] newArray = new double[rows];
for (int i = 0; i < rows; i++) {
for (int j = 0; j < columns; j++) {
newArray[i] += matrix[i][j] * array[i] * input[j];
loopCount++;
}
}
return newArray;
}

public static void main(String[] args) {
int rows = 100;
int columns = 128;
ArrayTest arrayTest = new ArrayTest(rows, columns);
Random random = new Random();
double[] input = new double[columns];
for (int i = 0; i < columns; i++) {
input[i] = random.nextDouble();
}
arrayTest.testOne(input, 5000);
arrayTest.testTwo(input, 5000);
}
}

最佳答案

您的测试花费不同时间的原因很简单:它们做的事情不同。由于您比较的两个循环在功能上并不相同,因此迭代次数不是一个很好的衡量标准。

testOnetestTwo 花费的时间更长,因为:

  • multOne 中,您在每次迭代期间就地更新 arrayOne[i]j 循环。这意味着对于内部循环 j 的每次迭代您正在使用 arrayOne[i]一个新值,在之前的迭代。这会创建一个循环携带的依赖项,即更难为编译器优化,因为你需要输出matrix[i][j] * arrayOne[i] * input[j] 操作的下一个CPU 时钟周期。这对于浮点来说是不可能的操作,通常有几个时钟周期的延迟,所以它会导致停顿,从而降低性能。

  • testTwo 中你每次 epoch 迭代仅更新一次 arrayOne,并且由于没有携带的依赖项,循环可以被矢量化高效,从而产生更好的缓存和算法性能。

关于java - 为什么减少循环次数并不能加快程序速度?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37600315/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com