Карта сайта Kansoftware
НОВОСТИУСЛУГИРЕШЕНИЯКОНТАКТЫ
Разработка программного обеспечения

when_all, heterogeneous types

Boost , Chapter 1. Fiber , when_all functionality

Boost C++ Libraries

...one of the most highly regarded and expertly designed C++ library projects in the world. Herb Sutter and Andrei Alexandrescu, C++ Coding Standards

PrevUpHomeNext

Но как насчет случая, когда надо ждать всех результатов разного типа?

Мы можем представить API, который, честно говоря, довольно крутой. Рассмотрим структуру выборки:

struct Data {
    std::string str;
    double      inexact;
    int         exact;
    friend std::ostream& operator<<( std::ostream& out, Data const& data);
    ...
};

Давайте заполним его членов из функций задач, работающих одновременно:

Data data = wait_all_members< Data >(
        [](){ return sleeper("wams_left", 100); },
        [](){ return sleeper(3.14,        150); },
        [](){ return sleeper(17,          50); });
std::cout << "wait_all_members<Data>(success) => " << data << std::endl;

Заметим, что для этого случая мы сначала отказываемся от понятия захвата самого раннего результата, и так далее: мы должны заполнить именно пройденную структуру в порядке слева направо.

Это позволяет реализовать очень просто:

// Explicitly pass Result. This can be any type capable of being initialized
// from the results of the passed functions, such as a struct.
template< typename Result, typename ... Fns >
Result wait_all_members( Fns && ... functions) {
    // Run each of the passed functions on a separate fiber, passing all their
    // futures to helper function for processing.
    return wait_all_members_get< Result >(
            boost::fibers::async( std::forward< Fns >( functions) ) ... );
}

template< typename Result, typename ... Futures >
Result wait_all_members_get( Futures && ... futures) {
    // Fetch the results from the passed futures into Result's initializer
    // list. It's true that the get() calls here will block the implicit
    // iteration over futures -- but that doesn't matter because we won't be
    // done until the slowest of them finishes anyway. As results are
    // processed in argument-list order rather than order of completion, the
    // leftmost get() to throw an exception will cause that exception to
    // propagate to the caller.
    return Result{ futures.get() ... };
}

Заманчиво попытаться реализовать wait_all_members() в качестве одного строки, как это:

return Result{ boost::fibers::async(functions).get()... };

Проблема с этой тактикой заключается в том, что она будет сериализовать все функции задачи. Среда выполнения делает один проход через функции , вызывая волокна::async() для каждого, а затем сразу же вызывая будущее::get() на его возвращенном будущее<>. Это блокирует скрытую петлю. Вышесказанное почти эквивалентно написанию:

return Result{ functions()... };

в котором, конечно, нет никакой параллели.

Пропуск пакета аргументов через границу вызова функции (wait_all_members_get()) вынуждает время выполнения совершать два прохода: один в wait_all_members() для сбора future<> из всех вызовов async(), второй в wait_all_members_get() для получения каждого из результатов.

Как отмечается в комментариях, в пределах wait_all_members_get() параметр расширения пакета становится неактуальным поведение блокировки get(). По пути мы нажмем get() для самой медленной функции задачи; после этого каждый последующий get() завершится в тривиальное время.

Кстати, мы также можем использовать этот же API для заполнения вектора или другой коллекции:

// If we don't care about obtaining results as soon as they arrive, and we
// prefer a result vector in passed argument order rather than completion
// order, wait_all_members() is another possible implementation of
// wait_all_until_error().
auto strings = wait_all_members< std::vector< std::string > >(
        [](){ return sleeper("wamv_left",   150); },
        [](){ return sleeper("wamv_middle", 100); },
        [](){ return sleeper("wamv_right",   50); });
std::cout << "wait_all_members<vector>() =>";
for ( std::string const& str : strings) {
    std::cout << " '" << str << "'";
}
std::cout << std::endl;


PrevUpHomeNext

Статья when_all, heterogeneous types раздела Chapter 1. Fiber when_all functionality может быть полезна для разработчиков на c++ и boost.




Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.



:: Главная :: when_all functionality ::


реклама


©KANSoftWare (разработка программного обеспечения, создание программ, создание интерактивных сайтов), 2007
Top.Mail.Ru

Время компиляции файла: 2024-08-30 11:47:00
2025-05-20 07:56:28/0.0081901550292969/1