Le 24/06/15 02:18, Giovanni Piero Deretta a écrit :
On Wed, Jun 24, 2015 at 12:09 AM, Vicente J. Botet Escriba
wrote: Hi,
Sean Parent suggests (See [1] Better Code: Concurrency) to remove the promise and left the packaged_task serve as single provider of a future. Both are created at once using the package factory.
Yes, packaged task is a far better producer side interface than a naked promise.
I like the idea of creating the future and promise (or better, packaged_task) together, although my preference would be a way to create the packaged task from the future, Yes, I don't see any major problem with this approach. future will then be default constructible also. which opens a lot of optimiation opportunities (for example if the future is non copyable non movable, no memory allocation is required). Sean' future is copyable and movable. Do you mean if the stored value? Are thinking of the future<void> specialization? When no memory allocation will be needed?
His future library doesn't include a shared_future as the future contains a value that can be observed several times. This is my biggest issue with Sean's design. Sharing the state among multiple consumes pretty much requires heavy weight synchronization. Could you elaborate? It this different for std::shared_future? But see below.
The continuation takes the value and not the future. So a future can have several continuations. What's the thread safety guarantees of future? 'As safe as int' or, for example, concurrent calls to .then are allowed? If the former, a copy could be a real deep copy (a new shared state is allocated and broadcasting is internally done via 'then'). That's not how Sean future is currently implemented though. Of course, concurrent calls to .then must be allowed. I don't see when would you need the copy of the shared state.
If the store type is movable only, then the future can have only one continuation. Not really strange coming from Sean, future and packaged_task are copyables :) One more thing, there is not get no wait, but a get_try that return an optional<T>.
Intresting, so if a consumer needs wait must implement it on top of then. This is fine, but you need a way to unregister a 'then'. I don't know. The std::experimental::future::then is the TS hasn't way to unregister a continuation. Why do you think it is needed now? It is because the future is shared?
Ah, I forget, as futures are executed using schedulers it is possible to cancel them (or cancel the execution of the associated packaged task).
Scales better. the interface is certanly nicer and simpler, but why do you think it scales better?
Hum, in fact it is independent of the split. It is because the futures created by async don't block on destruction.
[...]
What are you missing ? [...]
The when_any continuation probably needs to be passed the all the futures instead of just the value that is ready, so that it can be called recursively.
I would consider when_any as having associated a variant of the Ts as value type. The continuation should then be an overload of the alternatives. The continuation passed to all the futures could be an internal one that is called just once and cancelled just before the first call. Could you elaborate the recursive part?
when_any also requires the ability to unregister a continuation from a future, otherwise if called 'in a loop' the number of continuations associated with futures will grow.
You are right that they will grow. I'm wondering if this is a real interface issue or a QOI. Needs this use case a special consideration even if it could decrease the performances of more usual cases?
Implementing this eficiently is not trivial. Agreed.
-- gpd
Thanks for sharing you view, Vicente