Как правильно вернуть большие данные из std::future в C++11

Я немного озадачен тем, как правильно возвращать большие данные из асинхронной функции в 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
//                      ^^^^^^

Таким образом, очевидно, что при вызове функции в главном потоке возвращение значения elision или перемещение завершено. Но возвращаемое значение из будущего, очевидно, копируется вокруг. Кроме того, при попытке std::move в линиях, отмеченных MOVE[1,2]Время возврата из future.get() звонок остается прежним. С другой стороны, при возврате указателя это время возврата из future.get() незначительно (0 мс для меня).

Так должны ли большие данные возвращаться из фьючерса через указатель?

1 ответ

Решение

Проблема в том, что вы назначаете ret, который уже содержит результат вашего первого звонка test_return_of_large_vector, Тогда, как минимум, ваш код должен будет бесплатно 100000000 * sizeof int байт; перемещение-назначение vector::operator=(vector&&) указано, что он имеет постоянную сложность (для соответствующих распределителей), но деструктор источника перемещения займет время.

Если вы позвоните ret.clear(); ret.shrink_to_fit(); сначала "время возврата из будущего" уменьшается до 0 мс ( пример).

В качестве альтернативы вы можете просто переместить-создать другую переменную:

auto ret2 = future.get();                  // MOVE2
Другие вопросы по тегам