【问题标题】:Performance issue of std::move for different length of std::string不同长度的 std::string 的 std::move 性能问题
【发布时间】: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

有些地方让我很困惑。

  1. 如果不优化,为什么10bytes字符串和100bytes字符串速度一样?

  2. 为什么大多数时候复制比没有优化的移动要快?

  3. 为什么 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


【解决方案1】:

只是猜测,但是当您移动一个字符串时,您实际上是在删除另一个字符串的内容。在复制情况下不会发生这种情况。为什么不将所有字符串变量和操作移到一个单独的函数中并在该函数之外测量时间?你可能会有不同的结果。

【讨论】:

  • 是的,对于移动案例;释放所有单个字符串数据分配的成本包含在进行基准测试的循环中;对于复制情况,它发生在函数的末尾(当v 被销毁时)并且不被测量。
猜你喜欢
  • 2016-09-10
  • 2022-10-27
  • 1970-01-01
  • 2020-11-10
  • 1970-01-01
  • 2019-07-09
  • 2016-07-01
  • 2022-01-20
  • 2016-12-05
相关资源
最近更新 更多