我在这里测试了一些建议的方法。
我在一个容器/指针中分配了一个巨大的数据集(200GB):
编译器/操作系统:
g++ (Ubuntu 9.4.0-1ubuntu1~20.04.1) 9.4.0
设置:(c++-17,-O3 优化)
g++ --std=c++17 -O3
我使用linux-time计时整个程序的运行时间
1.) std::vector:
int main(){
constexpr size_t size = 1024lu*1024lu*1024lu*25lu;//25B elements = 200GB
std::vector<size_t> vec(size);
}
real 0m36.246s
user 0m4.549s
sys 0m31.604s
那是36秒。
2.) 使用boost::noinit_adaptor的std::vector
#include <vector>
#include <boost/core/noinit_adaptor.hpp>
int main(){
constexpr size_t size = 1024lu*1024lu*1024lu*25lu;
std::vector<size_t,boost::noinit_adaptor<std::allocator<size_t>>> vec(size);
}
real 0m0.002s
user 0m0.001s
sys 0m0.000s
所以这就解决了问题。只分配而不初始化基本上不会花费任何代价(至少对于大数组而言)。
3.) std::unique_ptr<T[]>:
int main(){
constexpr size_t size = 1024lu*1024lu*1024lu*25lu;//25B elements = 200GB
auto data = std::unique_ptr<size_t[]>(new size_t[size]);
}
real 0m0.002s
user 0m0.002s
sys 0m0.000s
基本上和2)一样的性能,但不需要使用boost。
我还测试了简单的new/delete和malloc/free,其性能与2)和3)相同。
因此,如果您处理大数据集,则默认构造可能会导致巨大的性能损失。
在实践中,您实际上希望在之后初始化分配的数据。
然而,一些性能惩罚仍然存在,特别是如果稍后的初始化是并行执行的。
例如,我使用(伪)随机数集初始化一个巨大的向量:
(现在我在24核AMD Threadripper 3960X上使用fopenmp进行并行化)
g++ --std=c++17-fopenmp -O3
1.) std::vector:
#include <vector>
#include <random>
int main(){
constexpr size_t size = 1024lu*1024lu*1024lu*25lu;
std::vector<size_t> vec(size);
#pragma omp parallel
{
std::minstd_rand0 gen(42);
#pragma omp for schedule(static)
for (size_t i = 0; i < size; ++i) vec[i] = gen();
}
}
real 0m41.958s
user 4m37.495s
sys 0m31.348s
这是42秒,仅比默认初始化多6秒。问题在于,std::vector的初始化是顺序的。
2.) 使用boost::noinit_adaptor的std::vector:
#include <vector>
#include <random>
#include <boost/core/noinit_adaptor.hpp>
int main(){
constexpr size_t size = 1024lu*1024lu*1024lu*25lu;
std::vector<size_t,boost::noinit_adaptor<std::allocator<size_t>>> vec(size);
#pragma omp parallel
{
std::minstd_rand0 gen(42);
#pragma omp for schedule(static)
for (size_t i = 0; i < size; ++i) vec[i] = gen();
}
}
real 0m10.508s
user 1m37.665s
sys 3m14.951s
即使使用随机初始化,由于我们可以跳过
std::vector
的顺序初始化,因此代码仍然快了4倍。
因此,如果您处理大型数据集并计划之后在并行中初始化它们,您应该避免使用默认的std::vector。