我进行了一些涉及
你可以在下面的代码中看到这些函数。有趣的是,调整向量的大小并覆盖元素是最快的。我认为在推入元素之前保留内存会提高性能。
我知道
std::vector
的快速基准测试。我从一个相对较小的100个整数的向量开始,并调用多种方法来填充它,使它包含1,000,000个整数。我的大部分函数都涉及清除元素并再次添加元素或创建新向量并将其移动或交换原向量。我还有一个函数只是调整向量的大小并覆盖元素。你可以在下面的代码中看到这些函数。有趣的是,调整向量的大小并覆盖元素是最快的。我认为在推入元素之前保留内存会提高性能。
我知道
std::vector::resize()
会重新调整向量大小以包含新的计数。根据cppreference:
如果当前大小小于计数,则附加并初始化值的副本。
resize()
应该比其他函数少构建100个整数。因此,在速度上的差异让我感到惊讶。我认为 resize()
会分配和初始化新元素,而保留只会分配内存。#include <algorithm>
#include <chrono>
#include <iostream>
constexpr int InitialSize = 100;
constexpr int NewSize = 1000000;
void overwrite(std::vector<int>& v)
{
v.resize(NewSize);
for (int i = 0; i < NewSize; ++i)
{
v[i] = i;
}
}
void clear(std::vector<int>& v)
{
v.clear();
v.reserve(NewSize);
for (int i = 0; i < NewSize; ++i)
{
v.push_back(i);
}
}
void swap(std::vector<int> &v)
{
std::vector<int> vnew;
vnew.reserve(NewSize);
for (int i = 0; i < NewSize; ++i)
{
vnew.push_back(i);
}
v.swap(vnew);
}
void move(std::vector<int> &v)
{
std::vector<int> vnew;
vnew.reserve(NewSize);
for (int i = 0; i < NewSize; ++i)
{
vnew.push_back(i);
}
v = std::move(vnew);
}
int main()
{
{
std::vector<int> v(InitialSize);
std::iota(v.begin(), v.end(), 1);
auto start = std::chrono::high_resolution_clock::now();
move(v);
auto finish = std::chrono::high_resolution_clock::now();
std::chrono::duration<double, std::milli> elapsed = finish - start;
std::cout << "Move - elapsed time: " << elapsed.count() << " ms" << std::endl;
}
{
std::vector<int> v(InitialSize);
std::iota(v.begin(), v.end(), 1);
auto start = std::chrono::high_resolution_clock::now();
clear(v);
auto finish = std::chrono::high_resolution_clock::now();
std::chrono::duration<double, std::milli> elapsed = finish - start;
std::cout << "Clear - elapsed time: " << elapsed.count() << " ms" << std::endl;
}
{
std::vector<int> v(InitialSize);
std::iota(v.begin(), v.end(), 1);
auto start = std::chrono::high_resolution_clock::now();
swap(v);
auto finish = std::chrono::high_resolution_clock::now();
std::chrono::duration<double, std::milli> elapsed = finish - start;
std::cout << "Swap - elapsed time: " << elapsed.count() << " ms" << std::endl;
}
{
std::vector<int> v(InitialSize);
std::iota(v.begin(), v.end(), 1);
auto start = std::chrono::high_resolution_clock::now();
overwrite(v);
auto finish = std::chrono::high_resolution_clock::now();
std::chrono::duration<double, std::milli> elapsed = finish - start;
std::cout << "Overwrite - elapsed time: " << elapsed.count() << " ms" << std::endl;
}
return 0;
}
输出:
Move - elapsed time: 14.6284 ms
Clear - elapsed time: 17.5072 ms
Swap - elapsed time: 12.9111 ms
Overwrite - elapsed time: 5.19079 ms
有人能解释一下这里到底发生了什么吗?
resize
可以使用一些avx
优化的memset
更高效地批量初始化成员,而push_back
则会逐个初始化它们。 - Tarek Dakhran-O3
。 - selbieint
。我怀疑使用非平凡类型会触发不同的优化路径并产生截然不同的结果。此外,一定要多次重复计时实验以获得结果的可信度。作为经验法则,你不应该少于20次重复实验。而且你应该像其他评论中建议的那样预热测试。 - bitmask