10. Теперь у нас есть функции, которые распараллеливаются автоматически и имеют такие же имена, что и оригинальные функции, но с префиксом p
"foo "
и "bar "
, которые мгновенно сконкатенируем в "foo bar "
. Эта строка будет сконкатенирована сама с собой с помощью функции twice. Затем создадим строки "this "
и "that "
, которые сконкатенируем в "this that "
. Наконец, сконкатенируем все эти строки в "foo bar foo bar this that "
. Результат будет сохранен в переменной callable
. Затем, наконец, вызовем функцию callable().get()
с целью начать вычисления и дождаться возвращаемых значений, чтобы вывести на экран и их. До вызова callable()
не выполняется никаких вычислений, а после этого вызова и начинается вся магия. auto result (
pconcat(
ptwice(
pconcat(
pcreate("foo "),
pcreate("bar "))),
pconcat(
pcreate("this "),
pcreate("that "))));
cout << "Setup done. Nothing executed yet.\n";
cout << result().get() << '\n';
}
11. Компиляция и запуск программы показывают, что все вызовы create
$ ./chains
Setup done. Nothing executed yet.
3s CREATE "foo "
3s CREATE "bar "
3s CREATE "this "
3s CREATE "that "
5s CONCAT "this " "that "
5s CONCAT "foo " "bar "
3s TWICE "foo bar "
5s CONCAT "foo bar foo bar " "this that "
foo bar foo bar this that
Как это работает
Простая последовательная версия этой программы без вызовов async
future
выглядела бы так:int main()
{
string result {
concat(
twice(
concat(
create("foo "),
create("bar "))),
concat(
create("this "),
create("that "))) };
cout << result << '\n';
}
В данном примере мы написали вспомогательные функции async_adapter
asynchronize
, которые позволили создать новые функции на основе функций create
, concat
и twice
. Мы назвали эти новые асинхронные функции pcreate
, pconcat
и ptwice
. Сначала опустим сложность реализации async_adapter
и asynchronize
с целью увидеть, что они дают. Последовательная версия выглядит аналогично следующему коду:string result {concat( ... )};
cout << result << '\n';
Распараллеленная версия выглядит аналогично этому фрагменту:
auto result (pconcat( ... ));
cout << result().get() << '\n';
Теперь перейдем к сложной части. Типом распараллеленного результата является не string
future
, для которого можно вызвать функцию get(). На первый взгляд это выглядит без умным.Как и зачем мы работаем с объектами, которые возвращают значения типа future
create
, concat
и twice
С левой стороны мы видим план для
create
длится 3 секунды, вызов concat
— 5 секунд, а twice
— 3 секунды, для получения конечного результата потребуется 30 секунд.