【问题标题】:How to properly return large data from a std::future in c++11如何在 c++11 中从 std::future 正确返回大数据
【发布时间】:2015-07-24 14:54:48
【问题描述】:

我有点困惑从 c++ 中的异步函数返回大数据的正确方法是什么。

以这段代码为例。它在函数中创建一个大向量并返回分配的向量。

#include <unistd.h>

#include <iostream>
#include <chrono>

#include <future>
#include <vector>

using timepoint = std::chrono::time_point<std::chrono::system_clock>;

timepoint start_return;

std::vector< int > test_return_of_large_vector(void)
{
    std::vector< int > ret(100000000);
    start_return = std::chrono::system_clock::now();
    return ret;                          // MOVE1
}


int main(void)
{

    timepoint start = std::chrono::system_clock::now();
    auto ret = test_return_of_large_vector();
    timepoint end = std::chrono::system_clock::now();

    auto dur_create_and_return = std::chrono::duration_cast< std::chrono::milliseconds >(end - start);
    auto dur_return_only = std::chrono::duration_cast< std::chrono::milliseconds >(end - start_return);

    std::cout << "create & return time : " << dur_create_and_return.count() << "ms\n";
    std::cout << "return time : " << dur_return_only.count() << "ms\n";

    auto future = std::async(std::launch::async, test_return_of_large_vector);
    sleep(3); // wait long enough for the future to finish its work

    start = std::chrono::system_clock::now();
    ret = future.get();                  // MOVE2
    end = std::chrono::system_clock::now();

    // mind that the roles of start and start_return have changed
    dur_return_only = std::chrono::duration_cast< std::chrono::milliseconds >(end - start);
    dur_create_and_return = std::chrono::duration_cast< std::chrono::milliseconds >(end - start_return);

    std::cout << "duration since future finished: " << dur_create_and_return.count() << "ms\n";
    std::cout << "return time from future: " << dur_return_only.count() << "ms\n";

    return 0;
}

对我来说这是打印出来的

create & return time : 543ms
return time : 0ms
duration since future finished: 2506ms
return time from future: 14ms
//                      ^^^^^^

显然,在主线程中调用函数时,返回值省略或移动已经完成。但是未来的返回值显然被复制了。此外,当在MOVE[1,2] 标记的行中尝试std::move 时,future.get() 调用的返回时间保持不变。另一方面,当返回一个指针时,future.get() 的返回时间可以忽略不计(我是 0 毫秒)。

那么大数据必须通过指针从future中返回吗?

【问题讨论】:

    标签: c++11 return-value-optimization stdasync


    【解决方案1】:

    问题是您分配ret,它已经保存了您第一次调用test_return_of_large_vector 的结果。那么,您的代码至少需要释放 100000000 * sizeof int 字节; vector::operator=(vector&amp;&amp;) 的移动赋值被指定为具有恒定复杂度(对于适当的分配器),但移动源的析构函数需要时间。

    如果你先调用ret.clear(); ret.shrink_to_fit();,那么“从未来返回的时间”会下降到 0 毫秒 (example)。

    或者你可以移动构造一个不同的变量:

    auto ret2 = future.get();                  // MOVE2
    

    【讨论】:

    • @PSIAlt future.get 仅针对 T &amp; 部分特化返回 T &amp;。对于泛型特化,它返回T,它作为纯右值绑定到右值引用。见en.cppreference.com/w/cpp/thread/future/get
    • 或者,简而言之,OP 分析了两个不同的操作,并将差异归咎于没有不同的东西。
    猜你喜欢
    • 2020-03-03
    • 2016-09-04
    • 1970-01-01
    • 2017-10-13
    • 1970-01-01
    • 1970-01-01
    • 2011-09-06
    • 2014-04-26
    • 1970-01-01
    相关资源
    最近更新 更多