[英]What is the performance penalty of using std::vector in C++?
通常,我很想知道标准模板库是否会在数值/科学计算的代码中产生性能/速度开销。
例如。 将数组声明为
double 2dmatrix [10][10]
会给我更多的表现
std::vector<std::vector<double> > 2dmatrix(10,std::vector<double>(10,0.0))
?
我还要感谢一些一般性的想法,关于C在科学计算方面是否具有比C ++更好的性能。 我使用STL以非常面向对象的方式编写了我的代码,并且使用了C ++ 11。 我开始考虑是否应该开始研究纯C,如果它运行得更快。
对此有任何想法都是受欢迎的。
鉴于它提供的抽象 ,C ++ std::vector
的效率与它一样高:栈上有3个指针,动态分配的数据在线性增长场景中平均每个元素重新分配1次(因为调整大小扩展了容量更多)比例,1.5至2)。
使用malloc()
和realloc()
的C等价物至少同样昂贵,而且更麻烦(手动调整大小等)。 此外, std::vector
允许通过特殊分配器 (基于池,堆栈分配等)进行用户定义的性能调优 ,这在C ++ 11中并不像在C ++ 98中那样难以使用。
如果不需要动态调整大小,可以在C和C ++中编写静态数组(或C ++中的std::array
)。
通常,对于高性能计算, C ++具有更多的优化潜力 ,特别是通过使用可以内联的函数对象(与常规C函数指针相比)。 规范的例子是排序
int comp( const void* a, const void* b ) {
return /* your comparison here */;
}
// C style sorting
qsort( arr, LARGE_SIZE, sizeof( int ), comp );
^^^^ <---- no-inlining through function pointer
// C++11 style sorting (use hand-made function object for C++98
std::sort(std::begin(arr), std::end(arr), [](auto a, auto b) {
return comp(&a, &b);
^^^^ <----- C++11 lambdas can be fully inlined
});
std :: vector的开销是:
在某些情况下(对于少量数据),堆栈分配的阵列可能更快。 为此,您可以使用std::array<T, Length>
。
如果你需要一个二维网格,我会在一个向量中分配数据: std::vector<T>(width * height);
。 然后你可以编写一些辅助函数来通过x和y坐标获取元素。 (或者你可以写一个包装类 。)
如果您事先知道大小并且性能是瓶颈 - 请使用C ++ 11中的std::array
。 它的性能与C风格的数组完全相同,因为它内部看起来像
template<typename T, int N>
struct array {
T _data[N];
};
这是在现代C ++中使用堆栈分配的数组的一种优先方式。 如果您有现代编译器,切勿使用C风格的数组。
如果您没有理由调整数组的大小,并且在编译期间知道它的大小(就像您在第一个示例中所做的那样),那么STL模板的更好选择是std::array
模板。 它为您提供C风格阵列的所有相同优点。
double 2dmatrix[10][10];
// would become
std::array<std::array<double, 10>, 10> 2dmatrix;
人们会说“这取决于你在做什么”。
他们是对的。
还有一个例子在这里 ,其中使用常规设计的程序std::vector
被调谐性能,通过一系列的六个阶段,并且其执行时间从每个工作单元2700微秒减少到3.7,为730X的加速因子。
首先要做的是注意到很大一部分时间用于增长数组并从中删除元素。 因此使用了不同的数组类,这大大减少了时间。
第二件事是注意到很大一部分时间仍然在进行与数组相关的活动。 因此,数组完全被删除,而使用链接列表,产生了另一个大的加速。
然后其他事情使用了大部分剩余时间,例如new
和delete
对象。 然后这些对象在自由列表中被回收,产生了另一个大的加速。 经过几个阶段之后,我们决定停止尝试,因为要找到改进的东西变得越来越难,而且加速被认为是足够的。
关键是 ,不要只是选择一些强烈推荐的东西,然后希望最好。 而是以这种或那种方式构建它,然后像这样进行性能调整,并愿意根据您看到的大部分时间花费在数据结构设计上进行重大更改。 并迭代它 。 您可以将存储方案从A更改为B,然后从B更改为C.这是完全可以的。
在科学计算中,错误和次优代码特别令人沮丧,因为大量数据被错误处理并浪费了宝贵的时间。
std::vector
可能是你的瓶颈或你最好的表演者,这取决于你对其内部运作的了解。 要特别注意reserve()
, insert()
, erase()
; 如果您的程序是线程化的,请考虑学习对齐和处理器缓存。
如果您尝试自己完成所有内存管理,尤其是在逐步向软件添加功能时,请考虑花时间确保一致性以及后来寻找错误的时间。 在一天结束时,std :: vector的开销将是您遇到的最少问题。
对于科学计算,使用专用的C ++矩阵库(例如Armadillo)会更好。 这不仅可以为您提供快速的阵列处理,还可以进行彻底调试的许多线性代数运算。
除了性能原因之外,使用专用的C ++矩阵库还可以大大降低代码的冗长度,减少错误,从而加快开发速度。 一个例子是使用C ++矩阵库,您不必担心内存管理。
最后,如果你真的需要进入低级别(即直接通过指针使用内存),C ++允许你“下降”到C级别。 在Armadillo中,这是通过.memptr()成员函数完成的。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.