Jas*_*.Pu 7 c++ performance std stdstring
我尝试了这些代码来比较std::copyandstd::string的构造函数。
#include <chrono>
#include <iostream>
#include <vector>
void construct_test() {
std::vector<uint8_t> raw_data;
for (int i = 0; i < 1000 * 1024; i++) {
raw_data.push_back(i % 256);
}
auto start = std::chrono::high_resolution_clock::now();
std::string target_data;
target_data = std::string(raw_data.begin(), raw_data.end());
auto finish = std::chrono::high_resolution_clock::now();
std::cout << "construct: " << std::chrono::duration_cast<std::chrono::microseconds>(finish -
start)
.count()
<< "us" << std::endl;
}
void copy_test() {
std::vector<uint8_t> raw_data;
for (int i = 0; i < 1000 * 1024; i++) {
raw_data.push_back(i % 256);
}
auto start = std::chrono::high_resolution_clock::now();
std::string target_data;
target_data.resize(raw_data.size());
std::copy(raw_data.begin(), raw_data.end(), target_data.begin());
auto finish = std::chrono::high_resolution_clock::now();
std::cout << "copy: " << std::chrono::duration_cast<std::chrono::microseconds>(finish -
start)
.count()
<< "us" << std::endl;
}
int main() {
construct_test();
copy_test();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
我得到了结果:
construct: 6245us
copy: 1087us
Run Code Online (Sandbox Code Playgroud)
std::copy速度快 6 倍!
这符合预期吗?如果有,原因是什么?
我搜索了很多将向量转换为字符串的方法,但没有人提到std::copy方法。我应该使用这种方式吗?有什么缺点吗?
正如评论者指出的那样,您的测试方法存在严重缺陷。一般来说,您必须多次运行操作(可能数百万或数十亿次)才能获得有意义的结果。否则,运行基准测试的顺序和日程安排等可能会给您带来截然不同的结果。
steady_clockoverhigh_resolution_clock进行基准测试(尽管在这种情况下这不太可能产生重大影响)construct_test()即可copy_test()使一个函数比另一个函数运行得更快。您可以使用google/benchmark (由QuickBench使用)来获得更有意义的结果。
除了您使用的两种方法之外,至少还有两种创建/覆盖字符串的方法:
// BenchmarkInit
std::string target_data = std::string(raw_data.begin(), raw_data.end());
// BenchmarkAssignmentOp
std::string target_data;
target_data = std::string(raw_data.begin(), raw_data.end());
// BenchmarkAssign
std::string target_data;
target_data.assign(raw_data.begin(), raw_data.end());
// BenchmarkCopy
std::string target_data;
target_data.resize(raw_data.size());
std::copy(raw_data.begin(), raw_data.end(), target_data.begin());
Run Code Online (Sandbox Code Playgroud)
我们得到 clang 15、libstdc++、-O3 的以下基准测试结果:

std::string最好使用构造函数,无论是否首先进行不必要的默认初始化。前两种方法std::memcpy内部使用,这应该是复制内存最快的方法。std::copy速度较慢,可能是因为.resize()需要首先将内存归零,并且没有很好地针对 进行优化memcpy,而是针对向量化内存操作进行优化。.assign速度要慢得多,可能是因为与 相比,部分循环展开较少std::copy,因此除了复制内存之外还有很多开销。即使使用适当的基准测试,您也可以看到意想不到的巨大差异,并且只有在查看装配时才能理解事物的意义。
我已经打开了一份错误报告,并且这个性能问题已由@JonathanWakely修复。