我有一个嵌套的for循环结构,现在我在每次迭代开始时重新声明向量:
void function (n1,n2,bound,etc){
for (int i=0; i<bound; i++){
vector< vector<long long> > vec(n1, vector<long long>(n2));
//about three more for-loops here
}
}
这允许我在每次迭代时“重新开始”,这很有效,因为我的内部操作主要是vec [a] [b] + =某个值的形式。但我担心大n1或大n2的速度很慢。我不知道vector / arrays / etc的底层架构,所以我不确定处理这种情况的最快方法是什么。我应该使用数组吗?我应该以不同方式清除它吗我应该完全不同地处理逻辑吗?
编辑:向量的大小在技术上不会改变每次迭代(但它可能会根据函数参数而改变)。我只是试图清除/等等,所以在所有其他情况下,程序的速度尽可能快。
编辑:
我的不同方法的结果:
Timings (for a sample set of data):
reclaring vector method: 111623 ms
clearing/resizing method: 126451 ms
looping/setting to 0 method: 88686 ms
答案 0 :(得分:12)
我明确偏爱小范围(例如,如果仅在那里使用,则在最内层循环中声明变量)但是对于大尺寸,这可能会导致大量分配。
所以如果这个循环是一个性能问题,尝试在循环外声明变量并仅在循环内清除它 - 但是,这仅在向量的(保留)大小停留时才有利相同。如果要调整向量的大小,那么无论如何都会得到重新分配。
不要使用原始数组 - 它不会给你带来任何好处,只会带来麻烦。
答案 1 :(得分:10)
以下是一些测试几种不同方法的代码。
#include <chrono>
#include <iostream>
#include <vector>
int main()
{
typedef std::chrono::high_resolution_clock clock;
unsigned n1 = 1000;
unsigned n2 = 1000;
// Original method
{
auto start = clock::now();
for (unsigned i = 0; i < 10000; ++i)
{
std::vector<std::vector<long long>> vec(n1, std::vector<long long>(n2));
// vec is initialized to zero already
// do stuff
}
auto elapsed_time = clock::now() - start;
std::cout << elapsed_time.count() << std::endl;
}
// reinitialize values to zero at every pass in the loop
{
auto start = clock::now();
std::vector<std::vector<long long>> vec(n1, std::vector<long long>(n2));
for (unsigned i = 0; i < 10000; ++i)
{
// initialize vec to zero at the start of every loop
for (unsigned j = 0; j < n1; ++j)
for (unsigned k = 0; k < n2; ++k)
vec[j][k] = 0;
// do stuff
}
auto elapsed_time = clock::now() - start;
std::cout << elapsed_time.count() << std::endl;
}
// clearing the vector this way is not optimal since it will destruct the
// inner vectors
{
auto start = clock::now();
std::vector<std::vector<long long>> vec(n1, std::vector<long long>(n2));
for (unsigned i = 0; i < 10000; ++i)
{
vec.clear();
vec.resize(n1, std::vector<long long>(n2));
// do stuff
}
auto elapsed_time = clock::now() - start;
std::cout << elapsed_time.count() << std::endl;
}
// equivalent to the second method from above
// no performace penalty
{
auto start = clock::now();
std::vector<std::vector<long long>> vec(n1, std::vector<long long>(n2));
for (unsigned i = 0; i < 10000; ++i)
{
for (unsigned j = 0; j < n1; ++j)
{
vec[j].clear();
vec[j].resize(n2);
}
// do stuff
}
auto elapsed_time = clock::now() - start;
std::cout << elapsed_time.count() << std::endl;
}
}
编辑:我已更新代码,以便在方法之间进行更公平的比较。 编辑2 :稍微清理一下代码,方法2或4是可行的方法。
以下是我计算机上上述四种方法的时间:
16327389
15216024
16371469
15279471
重点是你应该尝试不同的方法和 profile 你的代码。
答案 2 :(得分:5)
答案 3 :(得分:0)
为什么不这样:
{
vector< vector<long long> > vec(n1, vector<long long>(n2));
for (int i=0; i<bound; i++){
//about three more for-loops here
vec.clear();
}
}
修改:添加范围大括号; - )
答案 4 :(得分:0)
除了之前的评论:
如果你使用Robinson的交换方法,你可以通过异步处理这个交换来加快速度。
答案 5 :(得分:0)
如果你真的关心性能(并且你事先知道n1
和n2
的大小)但是不想使用C风格的数组,std::array
可能做你的朋友。
编辑:鉴于你的编辑,似乎std::array
不是一个合适的替代品,因为虽然矢量大小不会改变每次迭代,但在编译之前它仍然是未知的。
答案 6 :(得分:0)
由于你必须在每次迭代时将向量值重置为0,实际上,这个问题归结为“与循环内的计算相比,为向量分配和释放内存的成本便宜或昂贵”。
假设计算是算法中昂贵的部分,那么编码它的方式既清晰,简洁,显示预期的范围,并且可能与替代方法一样快。
如果但是你的计算和更新非常快并且向量的分配/释放相对昂贵,你可以使用std::fill
在结尾处将零填充回数组/每次迭代开始循环。
当然,唯一可以确定的方法是使用分析器进行测量。我怀疑你会发现你采取的方法不会成为任何形式的热点,你应该留下明显的代码。
答案 7 :(得分:-1)
使用向量与数组的开销很小,尤其是当您从向量中获得许多有用的功能时。在内部,向量分配一个数组。所以矢量是要走的路。