Boost logo

Boost :

Subject: Re: [boost] Common future base class (was Re: Boost.Fibermini-review September 4-13)
From: Agustín K-ballo Bergé (kaballo86_at_[hidden])
Date: 2015-09-06 21:30:53


On 9/6/2015 6:26 PM, Giovanni Piero Deretta wrote:
> On Sun, Sep 6, 2015 at 7:22 PM, Agustín K-ballo Bergé
> <kaballo86_at_[hidden]> wrote:
>> On 9/6/2015 1:35 PM, Peter Dimov wrote:
>>>
>>> Hartmut Kaiser wrote:
>>>
>>>> template <typename Future...>
>>>> requires(is_future<Future>)...
>>>> future<tuple<Future...>> when_all(Future &&... f)
>>>> {
>>>> (await f)...;
>>>> return make_tuple(std::forward<Future>(f)...);
>>>> }
>>>
>>>
>>> I've always found when_any much more interesting than when_all. Is it as
>>> trivial to implement with await as when_all?
>>>
>>
>> The await proposal already deals with heterogeneous futures (awaitable
>> types). It comes with traits and customization points on top of which it is
>> built. Using `await_suspend` one can attach a callback to an awaitable
>> object that fires when the future becomes ready (without consuming it).
>> An
>> heterogeneous `when_all` would be built on top of `await_suspend`, plain
>> `await` is optimal when one just want the semantic of `when_all`. Similarly,
>> an heterogeneous `when_any` would use `await_suspend` to attach a callback
>> to all awaitable objects, and the first callback to run would make the
>> resulting future ready (potentially but not necessarily canceling all other
>> callbacks).
>>
>
> In the last coroutine proposal (is it N4499). It seems that
> await_suspend(h) is guaranteed to work only if 'h' is of type
> coroutine_handle<P>.

I don't quite see this, nor the opposite. Luckily the proposal is still
in flux (and I seriously hope it goes into a TS first).

> Also, at least from the example implementation in
> N4286, await_suspend is not really more powerful than 'then'.
>
> In fact the previous when_all implementation and the when_any you've
> described can be implemented on top of 'then'.

I thought the concern was that `then` does a bit too much, it consumes
the future which would be problematic for `when_any` returning futures
that cannot re-obtain until all input futures are ready.

> The problematic scenario is performing wait_any multiple times on the
> same future set as the attached continuations will continue growing
> every time.

I have not consider this problematic, each call to `wait_any` will cause
one memory allocation and it will only release it once all input futures
are done. I have not done any specific experimentation on this topic, I
might reach the same conclusions as you once I do.

My prior experience with `wait_any` includes dealing with hundreds or
thousands of futures, going back and "unwaiting" each of them has not
ever been a viable approach for me.

> BTW, it is sort of possible (but quite inefficient) to attach a
> continuation to an unique future without consuming it:
>
> template<class T>
> future<void> when_ready(std::future<T>& x)
> {
> auto shared_x = x.share();
> x = shared_x.then([](auto&&x) { return x.get(); }

No, this ^ introduces a copyable requirement.

> return x.then([](auto&&) {});
> }
>
> future<T> x = ...;
>
>
> await when_ready(x);
> // or
> when_ready(x).then([] { /* do something */ });

Regards,

-- 
Agustín K-ballo Bergé.-
http://talesofcpp.fusionfenix.com

Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk