【问题标题】:How to iterate through a fixed tridimensional matrix efficiently (java)如何有效地迭代固定的三维矩阵(java)
【发布时间】:2021-08-19 23:13:43
【问题描述】:

作为我正在构建的程序的一部分,我需要遍历三维矩阵中的所有点。 在每一点上,我都需要执行一个以 int x, int y, int z 作为参数的方法。

三维矩阵总是具有相同的宽度(16)长度(16)和高度(256)。

什么是最高效的迭代方式?(我特别关心 CPU,不太关心内存使用)

据我所知,我认为这是最有效的方法,但如果它们更快,我愿意接受其他建议。

A.直接迭代:

public void doSomethingForAllPointsInMatrix(Matrix matrix){
  for(int x= 0; x<16; x++){
    for(int z = 0; z<16; z++){
      for(int y = 0; y<256; y++){
        matrix.doSomething(x,y,z);//A method out of my control without any alternatives
      }
    }
  }
}

B.迭代包含坐标的数组

private static final int[] zeroToFifteen; //Contains every number from 0 to 15
private static final int[] zeroToTwoHundredFiftyFive; //Contains every number from 0 to 255
public void doSomethingForAllPointsInMatrix(Matrix matrix){
  for(int x: zeroToFifteen){
    for(int z: zeroToFifteen){
      for(int y: zeroToTwoHundredFiftyFive){
        matrix.doSomething(x,y,z);//A method out of my control without any alternatives
      }
    }
  }
}

提前感谢您提供的任何帮助!

【问题讨论】:

  • 你可以试试这个,发布在一个类似的问题上:stackoverflow.com/a/2996752/8104777
  • 感谢链接,我已经检查过了,该线程的优化是针对不属于我的问题的内容
  • 在这两种情况下,您的方法都会被调用x*y*z 次。如果不知道您的方法究竟做了什么以及它返回了什么,就很难提出一种通用的优化方法。也许您只是过早/不必要地考虑性能。实现该功能,使用具有少量维度的多维数据集对其进行测试,并在遇到性能问题时再次提出您的问题。您可能需要查看的内容:查看是否有任何对称性以不使用相同的参数多次调用您的方法,查看 doSomething(xi,yi,zi)doSomething(xn,yn,zn) 之间是否存在任何模式。
  • 虽然我同意一般的优化方法会更好,但该方法是另一个程序的 API 的一部分,这是我无法控制的,并且没有其他替代方法,所以循环我只能优化,而不是方法本身。不过,我将在示例中添加更多信息。
  • 矩阵在内存中的布局会因为缓存的使用而有所不同。我认为您最好的选择是遍历矩阵以确保您访问连续数据。

标签: java performance loops 3d iteration


【解决方案1】:

计数循环已经是最有效的迭代机制之一。

您合并数组的想法表明您不知道数组上的 for-each 循环只是从零到数组长度的索引上的计数循环的语法糖。
换句话说,你的

public void doSomethingForAllPointsInMatrix(Matrix matrix){
  for(int x: zeroToFifteen){
    for(int z: zeroToFifteen){
      for(int y: zeroToTwoHundredFiftyFive){
        matrix.doSomething(x,y,z);//A method out of my control without any alternatives
      }
    }
  }
}

基本上等价于

  public void doSomethingForAllPointsInMatrix(Matrix matrix){
    for(int index1 = 0; index1 < zeroToFifteen.length; index1++){
      int x = zeroToFifteen[index1];
      for(int index2 = 0; index2 < zeroToFifteen.length; index2++){
        int z = zeroToFifteen[index2];
        for(int index3 = 0; index3 < zeroToTwoHundredFiftyFive.length; index3++){
          int y = zeroToTwoHundredFiftyFive[index3];
          matrix.doSomething(x,y,z);//A method out of my control without any alternatives
        }
      }
    }
  }

与第一种方法的计数循环的不同之处仅在于执行额外的数组操作,这不太可能提高性能。

由于你的界限是 2 的幂,你可以用一个循环来完成整个操作

public void doSomethingForAllPointsInMatrix(Matrix matrix) {
  for(int coord = 0; coord < 0x10000; coord++) {
    matrix.doSomething(coord >> 12, coord & 0xff, (coord >> 8)&0xf);
  }
}

减少条件句的数量。但是,实际性能取决于 JVM 的优化器如何利用它,并且它可能更好地处理嵌套循环。

因此,您只能尝试对方法进行基准测试,以找到“最佳”,而“最佳”可能会有所不同,具体取决于系统和 JVM 实现/版本。

正如 cmets 中所说,性能可能由 doSomething 所做的任何事情决定,如果处理顺序对您的程序逻辑并不重要,您应该尝试使用其他迭代顺序,因为它可能会影响缓存的使用方式.

【讨论】:

  • 我知道这两者在功能上是等价的,但我不确定在这种情况下它们是否编译为完全相同的代码,感谢您澄清这一点,并感谢您提出的替代方案。
猜你喜欢
  • 2017-06-06
  • 2018-08-01
  • 1970-01-01
  • 2014-05-14
  • 1970-01-01
  • 2013-10-25
  • 2017-06-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多