web-dev-qa-db-fra.com

Futures vs promesses

Je me confonds avec la différence entre un futur et une promesse.

Évidemment, ils ont des méthodes et des choses différentes, mais quel est le cas d'utilisation réel?

Est-ce ?:

  • lorsque je gère une tâche asynchrone, j'utilise future pour obtenir la valeur "à l'avenir"
  • lorsque je suis la tâche asynchrone, j'utilise promise comme type de retour pour permettre à l'utilisateur de tirer un avenir de ma promesse
118
Let_Me_Be

Future et Promise sont les deux côtés distincts d'une opération asynchrone.

std::promise est utilisé par le "producteur/écrivain" de l'opération asynchrone.

std::future est utilisé par le "consommateur/lecteur" de l'opération asynchrone.

La raison pour laquelle il est séparé dans ces deux "interfaces" distinctes est de masquer la fonctionnalité "écriture/définition" du "consommateur/lecteur".

auto promise = std::promise<std::string>();

auto producer = std::thread([&]
{
    promise.set_value("Hello World");
});

auto future = promise.get_future();

auto consumer = std::thread([&]
{
    std::cout << future.get();
});

producer.join();
consumer.join();

Une façon (incomplète) d'implémenter std :: async à l'aide de std :: promise pourrait être:

template<typename F>
auto async(F&& func) -> std::future<decltype(func())>
{
    typedef decltype(func()) result_type;

    auto promise = std::promise<result_type>();
    auto future  = promise.get_future();

    std::thread(std::bind([=](std::promise<result_type>& promise)
    {
        try
        {
            promise.set_value(func()); // Note: Will not work with std::promise<void>. Needs some meta-template programming which is out of scope for this question.
        }
        catch(...)
        {
            promise.set_exception(std::current_exception());
        }
    }, std::move(promise))).detach();

    return std::move(future);
}

En utilisant std::packaged_task qui est un assistant (c’est-à-dire qu’il fait ce que nous faisions précédemment) autour de std::promise vous pouvez effectuer les opérations suivantes, qui sont plus complètes et éventuellement plus rapides:

template<typename F>
auto async(F&& func) -> std::future<decltype(func())>
{
    auto task   = std::packaged_task<decltype(func())()>(std::forward<F>(func));
    auto future = task.get_future();

    std::thread(std::move(task)).detach();

    return std::move(future);
}

Notez que ceci est légèrement différent de std::async où le retourné std::future sera, une fois détruit, réellement bloqué jusqu'à ce que le thread soit terminé.

152
ronag