【发布时间】:2019-11-04 12:35:49
【问题描述】:
我最近注意到我的程序中的 std::move 用于 std::string 在某种程度上比直接复制分配慢。
例如,
#include <string>
#include <vector>
#include <chrono>
#include <iostream>
int main(int argc, char *argv[])
{
size_t len(atoi(argv[1]));
std::string str, tmp;
std::vector<std::string> v(1000000);
for (auto& i : v)
{
i.reserve(len);
for (size_t j(0); j < len; j++)
i.push_back('0' + (j % 10));
}
str.reserve(len);
std::chrono::duration<double, std::milli> d;
auto c(std::chrono::steady_clock::now());
for (size_t i(0); i < v.size(); i++)
{
//str = v[i]; // copy assignment
str = std::move(v[i]); // move
}
d = std::chrono::steady_clock::now() - c;
std::cout << d.count() << "ms\n";
}
我通过以下方式编译它:g++-8 -std=c++17 -o test test.cpp
以下是一些测试结果:
short string(10bytes) * 1000000
-O0:
copy: ~60ms
move: ~100ms
-O3:
copy: ~8.4ms
move: ~7.5ms
short string(100bytes) * 1000000
-O0:
copy: ~64ms
move: ~110ms
-O3:
copy: ~9.4ms
move: ~15ms
long string(1000bytes) * 1000000
-O0:
copy: ~190ms
move: ~107ms
-O3:
copy: ~107ms
move: ~16ms
有些地方让我很困惑。
如果不优化,为什么10bytes字符串和100bytes字符串速度一样?
为什么大多数时候复制比没有优化的移动要快?
为什么 O3 复制 1000 字节字符串的速度会降低?
********** 6/23 更新 **********
抱歉回复晚了。感谢所有的回放和 cmets。
我用一个大小等于“v”的向量来代替“str”,并将它的所有元素写入到最后一个文件中。
有了这个改变,结果更加合理,可以解决我的第一个和第二个问题。
small-string-optimization 使得在 10bytes 字符串情况下复制比移动更快,而我原程序中其他情况的结果会受到复制省略的影响。
下面是更合理的结果
short string(10bytes) * 1000000
-O0:
copy: ~66ms
move: ~98ms
-O3:
copy: ~9ms
move: ~9ms
short string(100bytes) * 1000000
-O0:
copy: ~185ms
move: ~99ms
-O3:
copy: ~73ms
move: ~7ms
long string(1000bytes) * 1000000
-O0:
copy: ~570ms
move: ~100ms
-O3:
copy: ~510ms
move: ~7ms
但是在这个结果中,我的第三个问题仍然存在。
我记得编译器会使用 simd 来改进 O2 或更高优化的复制,但在 100 字节和 1000 字节的情况下,复制的速度似乎并不显着。
【问题讨论】:
-
对于赋值/复制变体,编译器可能会意识到只有最后一个赋值对结果很重要,并消除了其余的赋值,但它不能对 @987654325 进行相同的分析@.
-
move会破坏v的内容 -
这可能与复制省略有关。 c++ 编译器遵循 as-if 规则:en.wikipedia.org/wiki/As-if_rule 但是,它可以打破 as-if 规则来复制项目。假设编译器知道您对复制的对象没有做任何事情,因此忽略副本可能是公平的。
-
直言不加优化何必在意。优化可能是由于小字符串优化。
-
重复使用与目标相同的字符串对象并不公平。不要忘记它必须与上次得到的东西有关。
标签: c++ performance c++11