- Фантастика и фэнтези
- Ироническое фэнтези
- Стимпанк
- Детективная фантастика
- Киберпанк
- Попаданцы
- LitRPG
- Космоопера
- Технофэнтези
- Городская фантастика
- Русское фэнтези
- Юмористическая фантастика
- Космическая фантастика
- Боевое фэнтези
- Эпическая фантастика
- Зарубежная фантастика
- Книги магов
- Мистика
- Разная фантастика
- Разное фэнтези
- Любовное фэнтези
- Романтическая фантастика
- Городское фентези
- Историческая фантастика
- Историческое фэнтези
- Социально-философская фантастика
- Сказочная фантастика
- Иностранное фэнтези
- Романтическое фэнтези
- Ироническая фантастика
- Ужасы и Мистика
- Постапокалипсис
- Героическая фантастика
- Фэнтези
- Научная Фантастика
- Социально-психологическая
- Альтернативная история
- Боевая фантастика
- Разная литература
- Пословицы, поговорки
- Шахматы
- Визуальные искусства
- Фанфик
- Авто и ПДД
- Военное
- Отраслевые издания
- Гиды, путеводители
- Зарубежная образовательная литература
- Военная история
- Цитаты из афоризмов
- Современная литература
- Великолепные истории
- Начинающие авторы
- Современная зарубежная литература
- Боевые искусства
- Изобразительное искусство, фотография
- Кино
- Литература 19 века
- Недвижимость
- Музыка, музыканты
- Готические новеллы
- Истории из жизни
- Культура и искусство
- Спецслужбы
- Зарубежная прикладная литература
- Музыка, танцы
- Подростковая литература
- Прочее
- Военная техника, оружие
- Газеты и журналы
- Периодические издания
- Домоводство, Дом и семья
- Любовные романы
- Экономическая литература
- Научные и научно-популярные книги
- О животных
- Биохимия
- Культурология
- Юриспруденция
- Политика
- Психотерапия
- Языкознание
- Научпоп
- Медицина
- Психология, личное
- Радиотехника
- Филология
- Педагогика
- Образовательная литература
- Деловая литература
- Физика
- Науки: разное
- Химия
- Воспитание детей, педагогика
- Детская психология
- Зарубежная публицистика
- Биология
- Архитектура
- Зарубежная психология
- Науки о космосе
- Социология
- Математика
- География
- Беременность, ожидание детей
- Литературоведение
- Транспорт, военная техника
- Обществознание
- Зоология
- География
- Альтернативная медицина
- Иностранные языки
- Ветеринария
- Рефераты
- Астрология
- Биофизика
- Экология
- История Европы
- Учебники
- Шпаргалки
- Государство и право
- Ботаника
- Религиоведение
- История
- Техническая литература
- Прочая научная литература
- Психология
- Детективы и Триллеры
- Справочная литература
- Проза
- Новелла
- Юмор
- Проза
- Историческая проза
- Русская современная проза
- Советская классическая проза
- Повести
- Очерки
- Эссе
- Рассказы
- Зарубежная современная проза
- Сентиментальная проза
- Зарубежная классика
- Афоризмы
- Эпистолярная проза
- Феерия
- Семейный роман/Семейная сага
- Разное
- Антисоветская литература
- Магический реализм
- Русская классическая проза
- Современная проза
- О войне
- Контркультура
- Классическая проза
- Поэзия, Драматургия
- Детская литература
- Детская фантастика
- Детские остросюжетные
- Детские стихи
- Детские приключения
- Внеклассное чтение
- Учебная литература
- Зарубежные детские книги
- Бизнес
- Загадки
- Книги для подростков
- Школьные учебники
- Детский фольклор
- Книги для дошкольников
- Детские детективы
- Детская познавательная и развивающая литература
- Буквари
- Прочая детская литература
- Сказка
- Детская проза
- Детская образовательная литература
- Юмор
- Документальные книги
- Бизнес
- Внешнеэкономическая деятельность
- Тайм-менеджмент
- Кадровый менеджмент
- О бизнесе популярно
- Управление, подбор персонала
- Бизнес
- Менеджмент и кадры
- Продажи
- Экономика
- Ценные бумаги и инвестиции
- Малый бизнес
- Делопроизводство, офис
- Корпоративная культура, бизнес
- Банковское дело
- Финансы
- Зарубежная деловая литература
- Ораторское искусство / риторика
- Личные финансы
- Интернет-бизнес
- Поиск работы
- Государственное и муниципальное управление
- Бухучет и аудит
- Работа с клиентами
- Менеджмент
- Краткое содержание
- Личная эффективность
- Переговоры
- Приключения
- Старинная литература
- Религия и духовность
- Компьютеры и Интернет
- Блог
Читаем без скачивания C++17 STL Стандартная библиотека шаблонов - Яцек Галовиц
Шрифт:
Интервал:
Закладка:
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 выполняются одновременно, а остальные вызовы — уже после них. Кажется, будто все они были спланированы интеллектуально. Вся программа работает 16 секунд. Если бы шаги выполнялись не параллельно, то для завершения программы потребовалось бы 30 секунд. Обратите внимание: для одновременного выполнения всех вызовов 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<string>, для которого можно вызвать функцию get(). На первый взгляд это выглядит без умным.
Как и зачем мы работаем с объектами, которые возвращают значения типа future? Проблема заключается в том, что наши методы create, concat и twice слишком медленные. (Да, мы искусственно их замедлили, поскольку пытались смоделировать реальные приложения, которые потребляют много времени ЦП.) Но мы определили, что дерево зависимостей, описывающее поток данных, имеет независимые части, пригодные для параллельного выполнения. Рассмотрим два примера планов (рис. 9.5).
С левой стороны мы видим план для одного ядра. Все вызовы функций нужно выполнять один за другим, поскольку у нас есть только один ЦП. Это значит, что, поскольку вызов функции create длится 3 секунды, вызов concat — 5 секунд, а twice — 3 секунды, для получения конечного результата потребуется 30 секунд.
С правой стороны мы видим план, где задачи выполняются максимально распараллеленно. В идеальном мире, где все компьютеры имеют четыре ядра, можно создать все подстроки одновременно, а затем сконкатенировать их. Минимальное время получения результата с оптимальным параллельным планом равно 16 секундам. Мы не можем ускорить выполнение программы, если не сделать сами вызовы функций быстрее. Имея всего четыре ядра ЦП, можно добиться этого времени выполнения. Мы достигли оптимального расписания. Как оно работает?
Мы могли бы просто написать следующий код:
auto a (async(launch::async, create, "foo "));
auto b (async(launch::async, create, "bar "));
auto c (async(launch::async, create, "this "));
auto d (async(launch::async, create, "that "));
auto e (async(launch::async, concat, a.get(), b.get()));
auto f (async(launch::async, concat, c.get(), d.get()));
auto g (async(launch::async, twice, e.get()));
auto h (async(launch::async, concat, g.get(), f.get()));
Это хорошее начало для a, b, c и d, которые представляют четыре подстроки. Они создаются асинхронно в фоновом режиме. К сожалению, этот код блокируется в строке, где мы инициализируем e. Чтобы сконкатенировать a и b, нужно вызвать get() для обеих подстрок, данный код будет заблокирован до тех пор, пока данные значения не будут готовы. Очевидно, это плохая идея, поскольку распаралелливание перестает быть паралелльным после первого вызова get(). Требуется более хорошая стратегия.
Задействуем сложные вспомогательные функции, которые мы написали. Первая из них — это asynchronize:
template <typename F>
static auto asynchronize(F f)
{
return [f](auto ... xs) {
return [=] () {
return async(launch::async, f, xs...);
};
};
}
При наличии функции int f(int, int) можно сделать следующее:
auto f2 ( asynchronize(f) );
auto f3 ( f2(1, 2) );
auto f4 ( f3() );
int result { f4.get() };
Функция f2 — это наша асинхронная версия функции f. Ее можно вызвать с теми же аргументами, что и функцию f, поскольку f2 подражает ей. Затем она возвращает вызываемый объект, который мы сохраняем в f3. Функция f3 теперь захватывает f и аргументы 1, 2, но пока ничего не вызывает. Это все делается ради захвата.
Теперь при вызове функции f3() мы наконец получаем объект типа future, поскольку f3() делает вызов async(launch::async,f,1,2);! В некотором смысле семантическое значение f3 заключается в следующем: «Получить захваченную функцию и аргументы, а затем передать их в вызов std::async».
Внутреннее лямбда-выражение, которое не принимает никаких аргументов, позволяет пойти по нестандартному пути. С его помощью можно настроить работу для параллельной отправки, но не нужно вызывать никаких блокирующих функций.