不要假设任何编写基准测试并测量每个可能的实现。请注意,编写良好的 perforce 测试非常棘手,因为优化器可能比您更聪明。
所以这里有一些基准:
#include <sstream>
#include <map>
#include <iomanip>
#include <algorithm>
#include <numeric>
#include <random>
using TestData = std::vector<std::pair<std::string, int>>;
std::string makeStringFor(size_t x)
{
std::ostringstream out;
out << std::setfill('0') << std::setw(6) << x;
return out.str();
}
TestData makeTestDataSorted(size_t n)
{
TestData r;
r.reserve(n);
size_t i = 0;
std::generate_n(std::back_inserter(r), n, [&i]() {
return std::pair{makeStringFor(++i), i};
});
return r;
}
TestData makeTestDataShuffled(size_t n)
{
auto data = makeTestDataSorted(n);
std::random_device rd;
std::mt19937 g(rd());
std::shuffle(data.begin(), data.end(), g);
return data;
}
static void CreateMapFormSortedDataInsert(benchmark::State& state) {
auto n = state.range(0);
auto data = makeTestDataSorted(n);
for (auto _ : state) {
benchmark::DoNotOptimize(data);
std::map<std::string, int> m;
for (auto& p : data) {
m.insert(m.end(), p);
}
benchmark::DoNotOptimize(m);
}
}
// Register the function as a benchmark
BENCHMARK(CreateMapFormSortedDataInsert)->RangeMultiplier(2)->Range(8, 8<<4);
static void CreateMapDirectlyFormSortedData(benchmark::State& state) {
auto n = state.range(0);
auto data = makeTestDataSorted(n);
for (auto _ : state) {
benchmark::DoNotOptimize(data);
std::map<std::string, int> m{data.begin(), data.end()};
benchmark::DoNotOptimize(m);
}
}
// Register the function as a benchmark
BENCHMARK(CreateMapDirectlyFormSortedData)->RangeMultiplier(2)->Range(8, 8<<4);
static void CreateMapFormShuffledDataInsert(benchmark::State& state) {
auto n = state.range(0);
auto data = makeTestDataShuffled(n);
for (auto _ : state) {
benchmark::DoNotOptimize(data);
std::map<std::string, int> m;
for (auto& p : data) {
m.insert(m.end(), p);
}
benchmark::DoNotOptimize(m);
}
}
// Register the function as a benchmark
BENCHMARK(CreateMapFormShuffledDataInsert)->RangeMultiplier(2)->Range(8, 8<<4);
static void FirstSortVectorThenCreateMap(benchmark::State& state) {
auto n = state.range(0);
auto data = makeTestDataShuffled(n);
for (auto _ : state) {
benchmark::DoNotOptimize(data);
auto sorted = data;
std::sort(sorted.begin(), sorted.end());
std::map<std::string, int> m;
for (auto& p : sorted) {
m.insert(m.end(), p);
}
benchmark::DoNotOptimize(m);
}
}
// Register the function as a benchmark
BENCHMARK(FirstSortVectorThenCreateMap)->RangeMultiplier(2)->Range(8, 8<<4);
结果:
调整这些测试,使它们更精确地匹配您的用例。这非常重要,请参阅最后一段。现在,如果您输入的数据已排序 insert 和 pos 参数看起来是最佳选择。
这也证明了std::vector中的数据先排序是没有意义的。
我也很惊讶直接从迭代器构建地图表现如此糟糕。 Caleth 在下面的评论中发现 std::pair 中的 const 有 surprising large impact here。将 const 添加到第一个类型构造函数后成为最快的选择。