当前位置: 首页 > 面试题库 >

Java使用数组的速度比C ++中std :: vector快8倍。我做错什么了?

方飞翼
2023-03-14
问题内容

我有以下带有几个大数组的Java代码,这些数组永远不会改变其大小。它在我的计算机上运行1100毫秒。

我在C ++中实现了相同的代码并使用std::vector

在我的计算机上,运行完全相同的代码的C ++实现的时间为8800 ms。我做错了什么,所以运行缓慢?

基本上,代码执行以下操作:

for (int i = 0; i < numberOfCells; ++i) {
        h[i] =  h[i] + 1;
        floodedCells[i] =  !floodedCells[i];
        floodedCellsTimeInterval[i] =  !floodedCellsTimeInterval[i];
        qInflow[i] =  qInflow[i] + 1;
}

它遍历大小约为20000的不同数组。

您可以在以下链接下找到这两种实现:

  • Java:https://ideone.com/R8KqjT
  • C ++:https://ideone.com/Lu7RpE

(由于时间限制,在ideone上,我只能运行400次而不是2000次循环。但是即使在这里,也有3次相差)


问题答案:

这是C ++版本,其中每个节点的数据收集到一个结构中,并使用该结构的单个向量:

#include <vector>
#include <cmath>
#include <iostream>



class FloodIsolation {
public:
  FloodIsolation() :
      numberOfCells(20000),
      data(numberOfCells)
  {
  }
  ~FloodIsolation(){
  }

  void isUpdateNeeded() {
    for (int i = 0; i < numberOfCells; ++i) {
       data[i].h = data[i].h + 1;
       data[i].floodedCells = !data[i].floodedCells;
       data[i].floodedCellsTimeInterval = !data[i].floodedCellsTimeInterval;
       data[i].qInflow = data[i].qInflow + 1;
       data[i].qStartTime = data[i].qStartTime + 1;
       data[i].qEndTime = data[i].qEndTime + 1;
       data[i].lowerFloorCells = data[i].lowerFloorCells + 1;
       data[i].cellLocationX = data[i].cellLocationX + 1;
       data[i].cellLocationY = data[i].cellLocationY + 1;
       data[i].cellLocationZ = data[i].cellLocationZ + 1;
       data[i].levelOfCell = data[i].levelOfCell + 1;
       data[i].valueOfCellIds = data[i].valueOfCellIds + 1;
       data[i].h0 = data[i].h0 + 1;
       data[i].vU = data[i].vU + 1;
       data[i].vV = data[i].vV + 1;
       data[i].vUh = data[i].vUh + 1;
       data[i].vVh = data[i].vVh + 1;
       data[i].vUh0 = data[i].vUh0 + 1;
       data[i].vVh0 = data[i].vVh0 + 1;
       data[i].ghh = data[i].ghh + 1;
       data[i].sfx = data[i].sfx + 1;
       data[i].sfy = data[i].sfy + 1;
       data[i].qIn = data[i].qIn + 1;


      for(int j = 0; j < nEdges; ++j) {
        data[i].flagInterface[j] = !data[i].flagInterface[j];
        data[i].typeInterface[j] = data[i].typeInterface[j] + 1;
        data[i].neighborIds[j] = data[i].neighborIds[j] + 1;
      }
    }

  }

private:

  const int numberOfCells;
  static const int nEdges = 6;
  struct data_t {
    bool floodedCells = 0;
    bool floodedCellsTimeInterval = 0;

    double valueOfCellIds = 0;
    double h = 0;

    double h0 = 0;
    double vU = 0;
    double vV = 0;
    double vUh = 0;
    double vVh = 0;
    double vUh0 = 0;
    double vVh0 = 0;
    double ghh = 0;
    double sfx = 0;
    double sfy = 0;
    double qInflow = 0;
    double qStartTime = 0;
    double qEndTime = 0;
    double qIn = 0;
    double nx = 0;
    double ny = 0;
    double floorLevels = 0;
    int lowerFloorCells = 0;
    bool floorCompleteleyFilled = 0;
    double cellLocationX = 0;
    double cellLocationY = 0;
    double cellLocationZ = 0;
    int levelOfCell = 0;
    bool flagInterface[nEdges] = {};
    int typeInterface[nEdges] = {};
    int neighborIds[nEdges] = {};
  };
  std::vector<data_t> data;

};

int main() {
  std::ios_base::sync_with_stdio(false);
  FloodIsolation isolation;
  clock_t start = clock();
  for (int i = 0; i < 400; ++i) {
    if(i % 100 == 0) {
      std::cout << i << "\n";
    }
    isolation.isUpdateNeeded();
  }
  clock_t stop = clock();
  std::cout << "Time: " << difftime(stop, start) / 1000 << "\n";
}

现场例子

现在的时间是Java版本速度的2倍。(846比1631)。

奇怪的是,JIT注意到缓存遍历整个地方访问数据的烧录,并将您的代码转换为逻辑上相似但效率更高的顺序。

我还关闭了stdio同步,这仅在将printf/ scanf与C
std::cout和混合使用时才需要 std::cin。碰巧的是,您只打印了一些值,但是C
的默认打印行为过于偏执且效率低下。

如果nEdges不是实际的常数值,则必须从中删除3个“数组”值struct。那不应该造成巨大的性能损失。

struct通过减小大小对值进行排序,从而减少内存占用量(并在无关紧要的情况下对访问进行排序),可能还可以提高性能。但是我不确定。

一条经验法则是,单个高速缓存未命中的开销比指令高100倍。安排数据具有缓存一致性具有很多价值。

如果struct无法将数据重新排列到中,则可以将迭代更改为依次遍历每个容器。

顺便说一句,请注意Java和C 版本在它们之间有一些细微的差异。我发现的一个问题是Java版本在“ for each edge”循环中有3个变量,而C

只有2个变量。我使我的代码与Java匹配。不知道还有没有



 类似资料:
  • 问题内容: 我有一个2 GB的文件(),其中文件中的每一行都是一个单词,就像: 我需要编写一个程序来读取文件中的每个单词并打印单词计数。我使用Java和C 编写它,但结果令人惊讶:Java运行速度是C 的2.3倍。我的代码如下: C ++: 输出: Java: 输出: 在这种情况下,为什么Java比C 快?如何提高C 的性能? 问题答案: 您不是在比较同一件事。Java程序读取行,以换行符开头,而

  • 问题内容: 我发现这一点的同时解决问题205的项目欧拉。问题如下: 彼得有九个四面(金字塔形)骰子,每个骰子的编号分别为1、2、3、4。科林有六个六边形(立方)骰子,每个骰子的编号为1、2、3、4、5、6。 彼得和科林掷骰子并比较总数:最高的总胜利数。如果总数相等,则结果为平局。 金字塔形皮特击败立方柯林的概率是多少?以0.abcdefg的形式将答案四舍五入到小数点后七个位 我用番石榴写了一个幼稚

  • 很长一段时间以来,我一直认为C比JavaScript快。然而,今天我制作了一个基准脚本来比较两种语言的浮点计算速度,结果令人惊叹! JavaScript似乎比C快近4倍! 我让这两种语言在我的i5-430M笔记本电脑上做同样的工作,执行了100000000次。C需要大约410毫秒,而JavaScript只需要大约120毫秒。 我真的不知道为什么JavaScript在这种情况下运行得这么快。有人能解

  • https://godbolt.org/z/P97MaK 我玩的概念和预期d::is_equality_comparable工作矢量,但它没有。 编译错误在 内部失败,而不是在受概念保护的函数边界处失败。 这是错误还是预期行为?

  • 我最近用Java写了一个计算密集型算法,然后把它翻译成C++。令我吃惊的是,C++的执行速度要慢得多。我现在已经编写了一个更短的Java测试程序,以及一个相应的C++程序-参见下面。我的原始代码具有大量的数组访问功能,测试代码也是如此。C++的执行时间要长5.5倍(请参阅每个程序末尾的注释)。 以下1st21条评论后的结论... null null Java代码: C++代码:

  • 问题内容: 试图了解如何比较数组。 苹果表示,阵列拷贝背后存在优化。看起来有时(并非总是)结构实际上是否被复制。 那就是 1)==遍历所有数组以执行基于元素的比较吗?(看起来像)->那么在非常大的阵列上的性能/内存使用情况如何? 2)我们确定如果所有元素都相等,==会返回true吗?我对Java字符串的==记忆犹新 3)有没有一种方法可以检查myArray1和myArray2在技术上是否使用相同的