我只想问问在处理二维数组时在性能和效率方面哪个更好,可能还有代码复杂性,因为我们需要为我们的小组项目制作一个矩阵库。
我在下面有一个代码(我认为这可能不是一个很好的例子,而且我的内存也有限,这就是为什么)
#include <iostream>
#include <chrono>
using namespace std;
using namespace std::chrono;
int main(){
auto start = high_resolution_clock::now();
auto arr2d = new unsigned long long int[10000ul][10000ul];
int cnt = 1;
for(unsigned long long int i=0; i<10000ul; ++i){
for(unsigned long long int j=0; j<10000ul; ++j){
arr2d[i][j] = cnt;
cnt++;
}
}
auto stop = high_resolution_clock::now();
auto duration = duration_cast<microseconds>(stop-start);
cout<<duration.count()<<endl;
auto start1 = high_resolution_clock::now();
auto arr1d = new unsigned long long int[100000000ull];
int cnt1 = 1;
for(unsigned long long int i=0; i<10000ul; ++i){
for(unsigned long long int j=0; j<10000ul; ++j){
arr1d[(i*10000ul)+j] = cnt1;
cnt1++;
}
}
auto stop1 = high_resolution_clock::now();
auto duration1 = duration_cast<microseconds>(stop1-start1);
cout<<duration1.count()<<endl;
return 0;
}
它表明性能并没有真正有太大的差异?
谁能给我们一个建议并解释我们应该走哪条路线?
答案 0 :(得分:3)
在您的特定情况下,您的两个 for 循环实际上都在按顺序访问内存,即使在二维数组的情况下(由于二维数组的内存布局),因此没有真正的区别。要查看一些不同的执行速度,请尝试以下模式:
for(unsigned long long int i=0; i<10000ull; ++i){
for(unsigned long long int j=0; j<10000ull; ++j){
arr2d[j][i] = 1-1*3+3/4; // note i and j are switched.
}
}
当您按顺序访问内存时,CPU 足够智能,可以将内存内容预取到 CPU 的 L1 和 L2 缓存中。但是在修改后的版本中,对内存的访问不是顺序的——每次都会提前10000*8个字节,CPU无法提前那么远的预取,所以代码会运行得更慢。
在你的代码中还有一点需要注意的是,表达式1-1*3+3/4
实际上会被编译器预先计算,因为它只包含常量,所以你的代码只会变成一系列的赋值。
答案 1 :(得分:0)
预计两种方法的性能是相同的。
二维数组,如 unsigned long long int[10000ul][10000ul]
占用单个连续的内存块,与具有相同元素数量的一维数组相同,如 unsigned long long int[100000000ull]
。这里没有区别。
着眼于访问数组中的元素,让我们通过假设 sizeof(unsigned long long)
为 8
来简化表示法。当您访问 arr2d[i][j]
时,编译器会将 (i*10000ul + j)*8
添加到 arr2d
的起始地址以查找该元素。当您访问 arr1d[(i*10000ul)+j]
时,编译器会将 ((i*10000ul)+j)*8
添加到 arr1d
的起始地址以查找该元素。这里没有区别。
这两种方法的底层实现没有区别,所以你应该使用更方便的。 然而, 在利用这个答案之前,请确保您使用的是二维数组(如 T [M][N]
中)而不是指向数组的指针数组(如 T* [M]
中)。使用一个的符号通常与另一个的符号没有区别,但是指针数组使用更多的内存并且不能保证所有内容都是连续的。这是否会显着影响代码的性能取决于执行的操作。 (虽然问题确实显示了一个真正的二维数组,但未来的读者可能会从这个警告中受益。)
说到方便,您可能会发现 std::vector
比自己管理内存更方便。但是,如果您选择使用矢量,您可能希望坚持使用一维方法。 std::vector< std::vector<unsigned long long int>>
中的嵌套向量类似于指针数组,因此您失去了单个连续内存块的好处。