Vector push_back 非常慢
Vector push_back incredibly slow
所以我正在将我编写的 Java 代码转换为 C++ 代码,出于性能原因以及使用 CUDA 并行化一些东西的意图。但是,我想做的第一件事是直接转换,并使用与 java.
中相同的代码让它在 C++ 中运行
我遇到的问题是下面的循环在 C++ 中确实需要几分钟才能完成,而在 Java 中几乎不需要任何时间。唯一的区别是我在 C++ 中使用向量,在 Java.
中使用 ArrayList
我还在最初创建单元向量时为邻居向量保留了适当的大小。这段代码的目的是在 3d 立方体中创建一个统一的单元格网格,并将每个单元格的邻居存储在单元格本身内部以方便以后使用。
我使用 Visual Studio 2013 以防万一(对于 C++)和 Eclipse java。
我觉得我在这里肯定遗漏了一些简单的东西,因为这样的减速看起来很疯狂,但是当我注释掉 push_back
时,代码基本上立即执行。
w
、h
、d
都是20
。 cells
是 Cell
结构的向量(见下文)。
for (int i = 0; i < w; i++) {
for (int j = 0; j < h; j++) {
for (int k = 0; k < d; k++) {
for (int x = -1; x < 2; x++) {
for (int y = -1; y < 2; y++) {
for (int z = -1; z < 2; z++) {
if (i + x >= 0 && i + x < w && j + y >= 0 && j + y < h && k + z >= 0 && k + z < d) {
cells[i][j][k].addNeighbor(cells[i + x][j + y][k + z]);
}
}
}
}
}
}
}
在不同的文件中定义:
struct Cell {
std::vector<Particle> particles;
std::vector<Cell> neighbors;
int b = 0;
void addParticle(Particle &p) {
particles.push_back(p);
}
void addNeighbor(Cell &c) {
neighbors.push_back(c);
}
};
在 C++ 中,vector
等标准容器按值存储其元素,而不是按引用(如 Java 中那样)。这意味着您的循环正在创建的单元格不仅 refer 到其他单元格,而且 contain 它们。您最终会创建一个巨大的嵌套向量森林,这些向量包含向量,它们本身也包含向量,依此类推(深度最多约 20 层!)。
您可能想要做的是存储指向相邻单元格的指针:
struct Cell {
...
std::vector<Cell*> neighbors;
...
void addNeighbor(Cell &c) {
neighbors.push_back(&c);
}
};
这允许单元格存储彼此的弱引用。
请记住,C++ 没有垃圾收集器,也没有做很多安全检查,因此您完全有责任确保在不再需要时释放单元格并且不再需要指针当单元格消失时取消引用。
对于Cells,上面的答案就足够了。但是对于粒子,会提出以下模型:
void addParticle(Particle &p) {
particles.push_back(p);
}
以上代码在内存中创建了大量的Particle对象,并进行了大量的数据拷贝。以下模型将节省内存分配和复制:
struct Cell {
std::vector<Particle> particles;
Particle& getNextParticleRefForUpdate()
{
particles.push_back(Particle());
return particles.at(particles.size() - 1);
}
...
};
粒子 class 将暴露集合函数:
struct Particle
{
int a;
int b;
void set(int& aval, int& bval)
{
a = aval;
b = bval;
}
...
};
在设置 Cell 对象的粒子对象时,该函数将执行以下操作:
Cell cell_val;
int aval = 5
int bval = 10;
Particle& par_val = cell_val.getNextParticleRefForUpdate();
par_val.set(aval, bval);
所以我正在将我编写的 Java 代码转换为 C++ 代码,出于性能原因以及使用 CUDA 并行化一些东西的意图。但是,我想做的第一件事是直接转换,并使用与 java.
中相同的代码让它在 C++ 中运行我遇到的问题是下面的循环在 C++ 中确实需要几分钟才能完成,而在 Java 中几乎不需要任何时间。唯一的区别是我在 C++ 中使用向量,在 Java.
中使用ArrayList
我还在最初创建单元向量时为邻居向量保留了适当的大小。这段代码的目的是在 3d 立方体中创建一个统一的单元格网格,并将每个单元格的邻居存储在单元格本身内部以方便以后使用。
我使用 Visual Studio 2013 以防万一(对于 C++)和 Eclipse java。
我觉得我在这里肯定遗漏了一些简单的东西,因为这样的减速看起来很疯狂,但是当我注释掉 push_back
时,代码基本上立即执行。
w
、h
、d
都是20
。 cells
是 Cell
结构的向量(见下文)。
for (int i = 0; i < w; i++) {
for (int j = 0; j < h; j++) {
for (int k = 0; k < d; k++) {
for (int x = -1; x < 2; x++) {
for (int y = -1; y < 2; y++) {
for (int z = -1; z < 2; z++) {
if (i + x >= 0 && i + x < w && j + y >= 0 && j + y < h && k + z >= 0 && k + z < d) {
cells[i][j][k].addNeighbor(cells[i + x][j + y][k + z]);
}
}
}
}
}
}
}
在不同的文件中定义:
struct Cell {
std::vector<Particle> particles;
std::vector<Cell> neighbors;
int b = 0;
void addParticle(Particle &p) {
particles.push_back(p);
}
void addNeighbor(Cell &c) {
neighbors.push_back(c);
}
};
在 C++ 中,vector
等标准容器按值存储其元素,而不是按引用(如 Java 中那样)。这意味着您的循环正在创建的单元格不仅 refer 到其他单元格,而且 contain 它们。您最终会创建一个巨大的嵌套向量森林,这些向量包含向量,它们本身也包含向量,依此类推(深度最多约 20 层!)。
您可能想要做的是存储指向相邻单元格的指针:
struct Cell {
...
std::vector<Cell*> neighbors;
...
void addNeighbor(Cell &c) {
neighbors.push_back(&c);
}
};
这允许单元格存储彼此的弱引用。
请记住,C++ 没有垃圾收集器,也没有做很多安全检查,因此您完全有责任确保在不再需要时释放单元格并且不再需要指针当单元格消失时取消引用。
对于Cells,上面的答案就足够了。但是对于粒子,会提出以下模型:
void addParticle(Particle &p) {
particles.push_back(p);
}
以上代码在内存中创建了大量的Particle对象,并进行了大量的数据拷贝。以下模型将节省内存分配和复制:
struct Cell {
std::vector<Particle> particles;
Particle& getNextParticleRefForUpdate()
{
particles.push_back(Particle());
return particles.at(particles.size() - 1);
}
...
};
粒子 class 将暴露集合函数:
struct Particle
{
int a;
int b;
void set(int& aval, int& bval)
{
a = aval;
b = bval;
}
...
};
在设置 Cell 对象的粒子对象时,该函数将执行以下操作:
Cell cell_val;
int aval = 5
int bval = 10;
Particle& par_val = cell_val.getNextParticleRefForUpdate();
par_val.set(aval, bval);