【问题标题】:How to move a result from an std::future in C++11?如何从 C++11 中的 std::future 移动结果?
【发布时间】:2020-03-03 02:28:39
【问题描述】:

我想在我的程序中异步处理std::vector<int>。然而,对象的检索不使用移动语义。

我创建了一个最小的工作示例并将其附在下面。根据cplusplus.com,只要它们共享相同的分配器(我使用的是标准一)。 再次根据cplusplus.com,当从std::future<T>::get()T 检索对象既不是void 也不是引用类型(不是这种情况)时,它的行为就像移动值一样。

我什至尝试只在第二个循环中使用inputs[i].get();,目前在 cmets 中,而不是将其分配给任何东西。这仍然会增加线性时间。

std::vector<std::vector<int>> GenerateTestCases(int input_size, int number_inputs) {
    std::vector<std::vector<int>> cases(number_inputs);

    for (auto i = 0; i < number_inputs; i++) {
        std::vector<int> some_vector(input_size);
        cases[i] = std::move(some_vector);
    }

    return std::move(cases);
}

int main() {
    for (auto i = 0; i < 25; i++) {
        auto size = (int)pow(2, i);
        int iterations = 100;

        auto test_cases = GenerateTestCases(size, iterations);

        std::vector<std::future<std::vector<int>>> inputs(iterations);

        const auto start = std::chrono::high_resolution_clock::now();

        for (auto i = 0; i < test_cases.size(); i++) {
            std::promise<std::vector<int>> prom;
            prom.set_value(std::move(test_cases[i]));

            inputs[i] = std::move(prom.get_future());
        }

        const auto middle = std::chrono::high_resolution_clock::now();

        for (auto i = 0; i < test_cases.size(); i++) {
            //inputs[i].get();
            auto& result = (inputs[i]);
            auto value = std::move(result.get());
        }

        const auto end = std::chrono::high_resolution_clock::now();

        const auto elapsed_first = std::chrono::duration_cast<std::chrono::nanoseconds>
        (middle - start).count();

        const auto elapsed_second = std::chrono::duration_cast<std::chrono::nanoseconds>
        (end - middle).count();

        std::cout << "First: " << elapsed_first << std::endl;
        std::cout << "Second: " << elapsed_second << std::endl;
        std::cout << std::endl;
    }

    char c;
    std::cin >> c;
}

但是,当我执行上面的代码时,我发现执行时间线性增加,范围从

第一个:13440ns 第二个:9919ns

对于最小的数组大小为

第一个:25919ns 第二个:300147450ns

最大的一个。

我在 Win10 上使用 VS2019 并为 x64 编译,如果这是出于兴趣的话。

【问题讨论】:

  • prom.get_future() 已经在返回一个 pr 值,顺便说一句。无需移动。
  • FWIW return std::move(cases); 几乎总是错误的。如果可以的话,函数本地对象已经在 return 语句中移动,所以这一切都是阻止编译器使用 NRVO。只需使用 return cases; 和“它会做正确的事”
  • @NathanOliver-ReinstateMonica 是吗?我认为 NRVO 以及该类别中的其他优化都留给编译器应用(或不应用)。另外:有什么痛?
  • 我会将GenerateTestCases 缩减为return std::vector&lt;std::vector&lt;int&gt;&gt;(number_inputs, std::vector&lt;int&gt;(input_size));
  • @SonneXo 使用 return std::move(cases); 会使编译器无法使用 NRVO。由于 NRVO 是一件好事,你不想停止它。如果您有return cases;,那么您可能会获得 NRVO,如果您没有,您仍然可以采取行动,因此不使用return std::move(cases); 是双赢的

标签: c++ c++11 move future


【解决方案1】:

时间成本可能来自于向量的销毁。


我做了一个测试,当结果保存在另一个向量中时时间不会增加(即防止破坏)

http://coliru.stacked-crooked.com/a/dc7792496a981de3


在您的原始代码中,时间确实增加了

http://coliru.stacked-crooked.com/a/66b96809fb35b3d2

【讨论】:

  • 我觉得我这里的英语语法很奇怪,但我现在无法正确理解,有人可以帮助我吗?我可能需要休息一下。 ://
  • 哇,我从没想过删除内存越大越费钱,更不用说这么大了!谢谢!
  • @SonneXo 这对我来说也有点令人惊讶。也许内存不足时会发生这种情况?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-19
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多