Отображение результатов, как только они будут готовы с помощью std :: async - PullRequest
5 голосов
/ 20 июня 2019

Я пытаюсь обнаружить асинхронное программирование на C ++.Вот игрушечный пример, который я использовал:

#include <iostream>
#include <future>
#include <vector>

#include <chrono>
#include <thread>

#include <random>

// For simplicity
using namespace std;

int called_from_async(int m, int n)
{
    this_thread::sleep_for(chrono::milliseconds(rand() % 1000));
    return m * n;
}

void test()
{
    int m = 12;
    int n = 42;

    vector<future<int>> results;

    for(int i = 0; i < 10; i++)
    {
        for(int j = 0; j < 10; j++)
        {
            results.push_back(async(launch::async, called_from_async, i, j));
        }
    }

    for(auto& f : results)
    {
        cout << f.get() << endl;
    }
}

Теперь этот пример не очень интересен, но он поднимает вопрос, который мне интересен.Допустим, я хочу отображать результаты по мере их поступления (я не знаю, что будет готово сначала, поскольку задержка случайна), как мне это сделать?

То, что я здесь делаю, явно неверно, так как я жду всех задач в том порядке, в котором я их создал - поэтому я буду ждать, пока первое выполнится, даже если оно длиннее других.

Я подумал о следующей идее: для каждого future, используя wait_for в течение небольшого времени, и, если оно готово, отобразите значение.Но я чувствую себя странно, делая это:

while (any_of(results.begin(), results.end(), [](const future<int>& f){
    return f.wait_for(chrono::seconds(0)) != future_status::ready;
}))
{
    cout << "Loop" << endl;
    for(auto& f : results)
    {
        auto result = f.wait_for(std::chrono::milliseconds(20));
        if (result == future_status::ready)
            cout << f.get() << endl;
    }
}

Это приносит еще одну проблему: мы будем вызывать get несколько раз на некоторых future с, что недопустимо:

прекращение вызова после выброса экземпляра 'std :: future_error'what (): std :: future_error: Нет связанного состояния

Так что я действительно не знаю, что здесь делать, предложите!

1 Ответ

4 голосов
/ 20 июня 2019

Используйте valid(), чтобы пропустить фьючерсы, для которых вы уже назвали get().

bool all_ready;
do {
    all_ready = true;
    for(auto& f : results) {
        if (f.valid()) {
            auto result = f.wait_for(std::chrono::milliseconds(20));
            if (result == future_status::ready) {
                cout << f.get() << endl;
            }
            else {
                all_ready = false;
            }
        }
    }
}
while (!all_ready);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...