Can anybody explain with an example in C++ what is the difference between async([](){x(); y();})
and async([](){x();}).then([](){y();})
? My understanding is that in the latter case each of x
, y
would possibly start in different threads immediately and would only block (in their respective thread) if a get()
was invoked on the future passed as input.
(since C++11) The class template std::future provides a mechanism to access the result of asynchronous operations: An asynchronous operation (created via std::async, std::packaged_task, or std::promise) can provide a std::future object to the creator of that asynchronous operation.
3) std::future is not CopyConstructible.
The class template std::promise provides a facility to store a value or an exception that is later acquired asynchronously via a std::future object created by the std::promise object.
... what is the difference between
async([](){x(); y();})
andasync([](){x();}).then([](){y();})
?
Not much really - so why have it then?
In a single word composability. It allows us to construct abstractions based on modular functions (or pieces of functionality) in an asynchronous environment in a expressive manner given the problem domain.
That is not to say the one is right and the other wrong - it just means that those semantics (of .then()
) is particularly meaningful when dealing with asynchronous operations.
The language of single threaded computations is something like "do this and do this and do this..." (before we carry on with other things), the language of asynchronous computation is "do this, and when it is done, then do this, and when it is done, then do this..." (while we carry on with other things).
Such a get()
can never block. This is by design in the relevant proposal, N3558.
#include <future> using namespace std; int main() { future<int> f1 = async([]() { return 123; }); future<string> f2 = f1.then([](future<int> f) { return f.get().to_string(); // here .get() won’t block }); }
[..]
Each continuation will not begin until the preceding has completed.
The benefit is that you can now compose several asynchronous operations in an expressive way. Could you just bundle all the code into a single lambda instead? Sure. But ew. Not re-usable and not particularly maintainable either.
Furthermore, there's some exception handling magic done for you. I suggest reading the proposal that defines what std::future::then
will actually do, though I admit that there's not much in the way of a "Rationale" section in there: it seems to focus on the downsides of blocking your main thread waiting for a future to complete, and doesn't mention your stated alternative use case. Well, maybe that's the problem: this feature isn't very much designed to replace it. That's why you're struggling to find the functional differences.
In asynchronous programming, it is very common for one asynchronous operation, on completion, to invoke a second operation and pass data to it. The current C++ standard does not allow one to register a continuation to a future. With .then, instead of waiting for the result, a continuation is “attached” to the asynchronous operation, which is invoked when the result is ready. Continuations registered using the .then function will help to avoid blocking waits or wasting threads on polling, greatly improving the responsiveness and scalability of an application.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With