Futures vs. Promesse


135

Mi sto confondendo con la differenza tra un futuro e una promessa.

Ovviamente, hanno metodi e cose diversi, ma qual è il caso d'uso reale?

È?:

  • quando gestisco alcune attività asincrone, utilizzo future per ottenere il valore "in futuro"
  • quando sono un compito asincrono, uso la promessa come tipo di ritorno per consentire all'utente di ottenere un futuro dalla mia promessa

1
Ho scritto un po 'su questo in questa risposta .
Kerrek SB,

1
possibile duplicato di What is std :: promise?
Nicol Bolas,

Risposte:


163

Futuro e Promessa sono i due lati separati di un'operazione asincrona.

std::promise viene utilizzato dal "produttore / scrittore" dell'operazione asincrona.

std::future viene utilizzato dal "consumatore / lettore" dell'operazione asincrona.

Il motivo per cui è separato in queste due "interfacce" separate è quello di nascondere la funzionalità "scrittura / imposta" al "consumatore / lettore".

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();

Un modo (incompleto) per implementare std :: async usando std :: promise potrebbe essere:

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);
}

L'utilizzo di std::packaged_taskche è un aiuto (ovvero che fa sostanzialmente quello che stavamo facendo sopra) intorno a std::promisete potrebbe fare quanto segue che è più completo e forse più veloce:

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);
}

Si noti che questo è leggermente diverso da std::asyncdove std::futureverrà restituito il blocco quando viene effettivamente distrutto fino al termine del thread.


3
@taras suggerisce che il ritorno std::move(something)è inutile e fa anche male (N) RVO. Ripristino della sua modifica.
polkovnikov.ph,

In Visual Studio 2015, utilizzare std :: cout << future.get (). C_str ();
Damian,

6
Per coloro che sono ancora confusi, vedi questa risposta .
kawing-chiu,

2
Questo è un produttore - consumatore, IMHO che in realtà non è un modello produttore - consumatore.
Martin Meeser,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.