Hi,

during my research, for the unwrapped GSoC proposal, I recognized that there is
an issue with my intended plan on providing mapper and traversal functions
for futures which are nested inside arbitrary variadic packs.
My plans are that I want to implement the two utility functions:

 - `map_futures` which can map futures inside arbitrary packs and containers.
 - `traverse_futures` which can visit futures inside arbitrary packs
   and containers (basically the same as the mapper functions however we
   don't return anything from the callable object).

The two functions could replace a lot of duplicated code in `unwrapped` as
well as many functions which are waiting on futures like `wait_all` or 
`when_all`.
A possible use-case could look like the following:

    int my_value = ...;
    hpx::future<int> my_future = ...;
    hpx::tuple<hpx::future<int>, hpx::future<float>> my_tuple = ...;

    // Can map futures to arbitrary values for unwrapping
    // we just call future::get...
    struct Mapper {
      template<typename T>
      T operator()(hpx::future<T> future) {
        return future.get();
      }
    };

    // Intended function for applying the given mapping to futures
    // which are nested in arbitrary packs
    hpx::tuple<int, int, hpx::tuple<int, float>> result =
      map_futures(Mapper{}, my_value, my_future, my_tuple);

    // Basically a mapper which maps nothing,
    // the nicer way would be to use C++14 variadic lambdas.
    struct Visitor {
      template<typename T>
      void operator()(hpx::future<T>& future) {
        // ...
      }
    };

    // Also there is a visitor function to let the given visitor
    // visit all futures, also further count limited visits shall be supported
    traverse_futures(Visitor{}, my_value, my_future, my_tuple);

However, `wait_all`, `when_all` and its similar functions, in which I planned
to use the proposed API, are currently implemented in a way that we start to 
wait
for the next future in a pack or container as soon as the previous one was 
resolved [0]:

    [request] -> future<int> -> future<int> -*
                                             |
                  [ready] <- future<int> <-- *

This approach requires that the wait functionality is suspendable and 
re-entrant able
which is difficult to implement in an efficient way, also the deferred execution
is requested sequentially and I guess that is not the intended behavior
when waiting for multiple futures at once.

Thus waiting for futures inside nested packs and containers becomes
much easier when we request the deferred execution for all futures and then
continue when all futures became ready (we could use an atomic counter
instead of the continuous usage of continuation handlers).
Basically this could be changed so that we are able to
use the API I proposed above:

        *-------- [request] --------*
        |            |              |
        V            V              V
    future<int>   future<int>   future<int>
         \            \             /
          \            v           /
           *-------> [ready] <----*

Is it possible to change the current request behavior of `when_all` and 
`wait_all`
so that we request the deferred execution of all futures, we wait on,
at once and then call the final continuation handler when all futures became 
ready?

I would highly appreciate it if you could return me a short feedback
if you think that the API I proposed above could be improved.

Best regards,
Denis

- [0] 
https://github.com/STEllAR-GROUP/hpx/blob/6941187bf1f3bf2c7c295d5f451d141f39ead6ec/hpx/lcos/wait_all.hpp#L247-L272
_______________________________________________
hpx-users mailing list
[email protected]
https://mail.cct.lsu.edu/mailman/listinfo/hpx-users

Reply via email to