Berjangka vs Janji

135

Saya membingungkan diri sendiri dengan perbedaan antara masa depan dan janji.

Jelas, mereka memiliki metode dan barang yang berbeda, tetapi apa kasus penggunaan yang sebenarnya?

Apakah itu?:

  • ketika saya mengelola beberapa tugas async, saya menggunakan masa depan untuk mendapatkan nilai "di masa depan"
  • ketika saya tugas async, saya menggunakan janji sebagai tipe kembali untuk memungkinkan pengguna mendapatkan masa depan dari janji saya
Šimon Tóth
sumber
1
Saya menulis sedikit tentang ini dalam jawaban ini .
Kerrek SB
1
kemungkinan rangkap dari Apa itu std :: janji?
Nicol Bolas

Jawaban:

163

Masa Depan dan Janji adalah dua sisi terpisah dari operasi asinkron.

std::promise digunakan oleh "produser / penulis" operasi asinkron.

std::future digunakan oleh "konsumen / pembaca" dari operasi asinkron.

Alasan dipisahkan menjadi dua "antarmuka" yang terpisah ini adalah untuk menyembunyikan fungsi "tulis / set" dari "konsumen / pembaca".

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

Salah satu (tidak lengkap) cara untuk mengimplementasikan std :: async menggunakan std :: janji bisa menjadi:

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

Menggunakan std::packaged_taskyang merupakan helper (yaitu pada dasarnya melakukan apa yang kami lakukan di atas) di sekitar std::promiseAnda dapat melakukan hal berikut yang lebih lengkap dan mungkin lebih cepat:

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

Perhatikan bahwa ini sedikit berbeda dari std::asynctempat yang dikembalikan std::futureakan ketika dihancurkan sebenarnya memblokir sampai utas selesai.

ronag
sumber
3
@taras menyarankan bahwa kembali std::move(something)tidak berguna dan juga menyakitkan (N) RVO. Mengembalikan suntingannya.
polkovnikov.ph
Di Visual Studio 2015 silakan gunakan std :: cout << future.get (). C_str ();
Damian
6
Bagi yang masih bingung, lihat jawaban ini .
kawing-chiu
2
Itu adalah produsen satu kali - konsumen, IMHO yang sebenarnya bukan produsen - pola konsumen.
Martin Meeser