c++ - 大数组通过引用传递
cpp - large array pass by reference
我有一个非常大的数组,其中包含大约 10000000 个双项(在下面的代码中,这个数字设置为 NX=1000,但实际上在实际情况下它将是 10000000)。我想用这个数组做一些计算,从中得到一个新数组。然后我再次用这个新数组进行一些计算等等。我正在寻找对 RAM 进行这些操作的最有效方法(我相信这是这里的限制因素,因为我的 arras 太大了)。我知道由于数组很大,我应该尝试尽可能多地传递每个引用的数组。但是我在将数组传递给其他函数时遇到问题。这是代码:
#include <iostream>
#include <array>
#define NX 1000
////////////////////////
//Function declaration//
////////////////////////
void time_propagation(std::array<double,NX>& X1,std::array<double,NX>& X2, double dt);
std::array<double,NX> F(std::array<double,NX>& X);
///////////////////////
//operator overloading/
///////////////////////
// double* Array
std::array<double,NX> operator*(double d,std::array<double,NX> X){
std::array<double,NX> res={};
for(int i=0;i<NX;i++){
res[i]=X[i]*d;
}
return res;
}
//Array + Array
std::array<double,NX> operator+(std::array<double,NX> X1,std::array<double,NX> X2){
std::array<double,NX> res={};
for(int i=0;i<NX;i++){
res[i]=X1[i]+X2[i];
}
return res;
}
/////////////
//main()/////
/////////////
int main () {
std::array<double,NX> X0={};
std::array<double,NX> X1 = {};
time_propagation(X0,X1,0.1);
//Now I will write X0 to a file. Afterwards X0 is not needed anymore. Only X1. Do I have to manually delete X0?
std::array<double,NX> X2 = {};
time_propagation(X1,X2,0.1);
//Now I will write X1 to a file. Afterwards X1 is not needed anymore. Only X2. Do I have to manually delete X1?
//... I have to do this step very often
return 0;
}
///////////////////////
//Function definitons//
///////////////////////
std::array<double,NX> F(std::array<double,NX>& X){
std::array<double,NX> R={};
double a=X[NX-2];
double b=X[NX-1];
R[NX-1]=-a;
R[NX-1]=3.0;
return R;
}
void time_propagation(std::array<double,NX>& X1,std::array<double,NX>& X2,double dt){
std::array<double,NX> K1=F(X1);
std::array<double,NX> K2=F(X1+dt/2.0*K1);
std::array<double,NX> K3=F(X1+dt/2.0*K2);
std::array<double,NX> K4=F(X1+dt*K3);
X2=X1+1.0/6.0*dt*(K1+2.0*K2+2.0*K3+K4);
}
我知道我的错误在函数“time_propagation”中。在倒数第五行中,我使用参数“X1+dt/2.0*K1”调用函数“F”。 “X1”是通过引用传递的,“K1”是之前定义的。我是否必须首先创建一个副本并在该副本上调用该函数?类似的东西:
void time_propagation(std::array<double,NX>& X1,std::array<double,NX>& X2,double dt){
std::array<double,NX> argument={};
for(int i=0;i<NX;i++){argument[i]=X1[i];}
std::array<double,NX> K1=F(argument);
for(int i=0;i<NX;i++){argument[i]=X1[i]+dt/2.0*K1[i];}
std::array<double,NX> K2=F(argument);
for(int i=0;i<NX;i++){argument[i]=X1[i]+dt/2.0*K2[i];}
std::array<double,NX> K3=F(argument);
for(int i=0;i<NX;i++){argument[i]=X1[i]+dt/2.0*K3[i];}
std::array<double,NX> K4=F(argument);
for(int i=0;i<NX;i++){X2[i]=X1[i]+1.0/6.0*dt*(K1[i]+2.0*K2[i]+2.0*K3[i]+K4[i]); }
}
如果我使用这个新的“time_propagation”函数,那么我不会再收到任何错误,但我的感觉是这个解决方法非常糟糕,有更好的方法吗?其次,也是最重要的,即使使用这个新版本的“time_propagation()”,如果我将 NX 增加到 10000000,我也会得到“分段错误(核心转储)”。我猜这是因为代码写得非常糟糕?一般来说,我的笔记本电脑应该能够在 RAM 中存储 10000000 个双精度数?我有 16 GB 的 RAM...而 10000000 个双打只需要 0.2 GB 的 RAM!?
根据您的评论,您已经非常接近答案了。您错过的一件事是,除了数组是基于堆栈的而向量是基于堆的之外,array
和 vector
之间还有一个区别:向量需要调用其构造函数(或调整大小)以扩大大小.所以切换到vector
后,我们需要稍微修改一下。
- 如何减少内存使用?
将不需要的复制参数改为引用。
- 如何手动回收向量?
使用 lambda 调用 swap
或 clear
和 shrink_to_fit
奖励:要删除 operator *
和 operator +
中不必要的临时对象,请参阅 Expression_templates
固定代码可能是这样的:
#include <array>
#include <iostream>
#include <vector>
#define NX 1000
////////////////////////
// Function declaration//
////////////////////////
void time_propagation(std::vector<double>& X1, std::vector<double>& X2,
double dt);
std::vector<double> F(const std::vector<double>& X);
///////////////////////
// operator overloading/
///////////////////////
// double* Array
std::vector<double> operator*(double d, const std::vector<double>& X) {
std::vector<double> res(NX);
for (int i = 0; i < NX; i++) {
res[i] = X[i] * d;
}
return res;
}
// Array + Array
std::vector<double> operator+(const std::vector<double>& X1,
const std::vector<double>& X2) {
std::vector<double> res(NX);
for (int i = 0; i < NX; i++) {
res[i] = X1[i] + X2[i];
}
return res;
}
/////////////
// main()/////
/////////////
int main() {
auto release_vec = [](auto& vec) {
vec.clear();
vec.shrink_to_fit();
};
std::vector<double> X0(NX);
std::vector<double> X1(NX);
time_propagation(X0, X1, 0.1);
// Now I will write X0 to a file. Afterwards X0 is not needed anymore. Only
// X1. Do I have to manually delete X0?
release_vec(X0);
std::vector<double> X2(NX);
time_propagation(X1, X2, 0.1);
// Now I will write X1 to a file. Afterwards X1 is not needed anymore. Only
// X2. Do I have to manually delete X1?
//... I have to do this step very often
release_vec(X1);
return 0;
}
///////////////////////
// Function definitons//
///////////////////////
std::vector<double> F(const std::vector<double>& X) {
std::vector<double> R(NX);
double a = X[NX - 2];
double b = X[NX - 1];
R[NX - 1] = -a;
R[NX - 1] = 3.0;
return R;
}
void time_propagation(std::vector<double>& X1, std::vector<double>& X2,
double dt) {
std::vector<double> K1 = F(X1);
std::vector<double> K2 = F(X1 + dt / 2.0 * K1);
std::vector<double> K3 = F(X1 + dt / 2.0 * K2);
std::vector<double> K4 = F(X1 + dt * K3);
X2 = X1 + 1.0 / 6.0 * dt * (K1 + 2.0 * K2 + 2.0 * K3 + K4);
}
我有一个非常大的数组,其中包含大约 10000000 个双项(在下面的代码中,这个数字设置为 NX=1000,但实际上在实际情况下它将是 10000000)。我想用这个数组做一些计算,从中得到一个新数组。然后我再次用这个新数组进行一些计算等等。我正在寻找对 RAM 进行这些操作的最有效方法(我相信这是这里的限制因素,因为我的 arras 太大了)。我知道由于数组很大,我应该尝试尽可能多地传递每个引用的数组。但是我在将数组传递给其他函数时遇到问题。这是代码:
#include <iostream>
#include <array>
#define NX 1000
////////////////////////
//Function declaration//
////////////////////////
void time_propagation(std::array<double,NX>& X1,std::array<double,NX>& X2, double dt);
std::array<double,NX> F(std::array<double,NX>& X);
///////////////////////
//operator overloading/
///////////////////////
// double* Array
std::array<double,NX> operator*(double d,std::array<double,NX> X){
std::array<double,NX> res={};
for(int i=0;i<NX;i++){
res[i]=X[i]*d;
}
return res;
}
//Array + Array
std::array<double,NX> operator+(std::array<double,NX> X1,std::array<double,NX> X2){
std::array<double,NX> res={};
for(int i=0;i<NX;i++){
res[i]=X1[i]+X2[i];
}
return res;
}
/////////////
//main()/////
/////////////
int main () {
std::array<double,NX> X0={};
std::array<double,NX> X1 = {};
time_propagation(X0,X1,0.1);
//Now I will write X0 to a file. Afterwards X0 is not needed anymore. Only X1. Do I have to manually delete X0?
std::array<double,NX> X2 = {};
time_propagation(X1,X2,0.1);
//Now I will write X1 to a file. Afterwards X1 is not needed anymore. Only X2. Do I have to manually delete X1?
//... I have to do this step very often
return 0;
}
///////////////////////
//Function definitons//
///////////////////////
std::array<double,NX> F(std::array<double,NX>& X){
std::array<double,NX> R={};
double a=X[NX-2];
double b=X[NX-1];
R[NX-1]=-a;
R[NX-1]=3.0;
return R;
}
void time_propagation(std::array<double,NX>& X1,std::array<double,NX>& X2,double dt){
std::array<double,NX> K1=F(X1);
std::array<double,NX> K2=F(X1+dt/2.0*K1);
std::array<double,NX> K3=F(X1+dt/2.0*K2);
std::array<double,NX> K4=F(X1+dt*K3);
X2=X1+1.0/6.0*dt*(K1+2.0*K2+2.0*K3+K4);
}
我知道我的错误在函数“time_propagation”中。在倒数第五行中,我使用参数“X1+dt/2.0*K1”调用函数“F”。 “X1”是通过引用传递的,“K1”是之前定义的。我是否必须首先创建一个副本并在该副本上调用该函数?类似的东西:
void time_propagation(std::array<double,NX>& X1,std::array<double,NX>& X2,double dt){
std::array<double,NX> argument={};
for(int i=0;i<NX;i++){argument[i]=X1[i];}
std::array<double,NX> K1=F(argument);
for(int i=0;i<NX;i++){argument[i]=X1[i]+dt/2.0*K1[i];}
std::array<double,NX> K2=F(argument);
for(int i=0;i<NX;i++){argument[i]=X1[i]+dt/2.0*K2[i];}
std::array<double,NX> K3=F(argument);
for(int i=0;i<NX;i++){argument[i]=X1[i]+dt/2.0*K3[i];}
std::array<double,NX> K4=F(argument);
for(int i=0;i<NX;i++){X2[i]=X1[i]+1.0/6.0*dt*(K1[i]+2.0*K2[i]+2.0*K3[i]+K4[i]); }
}
如果我使用这个新的“time_propagation”函数,那么我不会再收到任何错误,但我的感觉是这个解决方法非常糟糕,有更好的方法吗?其次,也是最重要的,即使使用这个新版本的“time_propagation()”,如果我将 NX 增加到 10000000,我也会得到“分段错误(核心转储)”。我猜这是因为代码写得非常糟糕?一般来说,我的笔记本电脑应该能够在 RAM 中存储 10000000 个双精度数?我有 16 GB 的 RAM...而 10000000 个双打只需要 0.2 GB 的 RAM!?
根据您的评论,您已经非常接近答案了。您错过的一件事是,除了数组是基于堆栈的而向量是基于堆的之外,array
和 vector
之间还有一个区别:向量需要调用其构造函数(或调整大小)以扩大大小.所以切换到vector
后,我们需要稍微修改一下。
- 如何减少内存使用?
将不需要的复制参数改为引用。
- 如何手动回收向量?
使用 lambda 调用 swap
或 clear
和 shrink_to_fit
奖励:要删除 operator *
和 operator +
中不必要的临时对象,请参阅 Expression_templates
固定代码可能是这样的:
#include <array>
#include <iostream>
#include <vector>
#define NX 1000
////////////////////////
// Function declaration//
////////////////////////
void time_propagation(std::vector<double>& X1, std::vector<double>& X2,
double dt);
std::vector<double> F(const std::vector<double>& X);
///////////////////////
// operator overloading/
///////////////////////
// double* Array
std::vector<double> operator*(double d, const std::vector<double>& X) {
std::vector<double> res(NX);
for (int i = 0; i < NX; i++) {
res[i] = X[i] * d;
}
return res;
}
// Array + Array
std::vector<double> operator+(const std::vector<double>& X1,
const std::vector<double>& X2) {
std::vector<double> res(NX);
for (int i = 0; i < NX; i++) {
res[i] = X1[i] + X2[i];
}
return res;
}
/////////////
// main()/////
/////////////
int main() {
auto release_vec = [](auto& vec) {
vec.clear();
vec.shrink_to_fit();
};
std::vector<double> X0(NX);
std::vector<double> X1(NX);
time_propagation(X0, X1, 0.1);
// Now I will write X0 to a file. Afterwards X0 is not needed anymore. Only
// X1. Do I have to manually delete X0?
release_vec(X0);
std::vector<double> X2(NX);
time_propagation(X1, X2, 0.1);
// Now I will write X1 to a file. Afterwards X1 is not needed anymore. Only
// X2. Do I have to manually delete X1?
//... I have to do this step very often
release_vec(X1);
return 0;
}
///////////////////////
// Function definitons//
///////////////////////
std::vector<double> F(const std::vector<double>& X) {
std::vector<double> R(NX);
double a = X[NX - 2];
double b = X[NX - 1];
R[NX - 1] = -a;
R[NX - 1] = 3.0;
return R;
}
void time_propagation(std::vector<double>& X1, std::vector<double>& X2,
double dt) {
std::vector<double> K1 = F(X1);
std::vector<double> K2 = F(X1 + dt / 2.0 * K1);
std::vector<double> K3 = F(X1 + dt / 2.0 * K2);
std::vector<double> K4 = F(X1 + dt * K3);
X2 = X1 + 1.0 / 6.0 * dt * (K1 + 2.0 * K2 + 2.0 * K3 + K4);
}