- Фантастика и фэнтези
- Ироническое фэнтези
- Стимпанк
- Детективная фантастика
- Киберпанк
- Попаданцы
- LitRPG
- Космоопера
- Технофэнтези
- Городская фантастика
- Русское фэнтези
- Юмористическая фантастика
- Космическая фантастика
- Боевое фэнтези
- Эпическая фантастика
- Зарубежная фантастика
- Книги магов
- Мистика
- Разная фантастика
- Разное фэнтези
- Любовное фэнтези
- Романтическая фантастика
- Городское фентези
- Историческая фантастика
- Историческое фэнтези
- Социально-философская фантастика
- Сказочная фантастика
- Иностранное фэнтези
- Романтическое фэнтези
- Ироническая фантастика
- Ужасы и Мистика
- Постапокалипсис
- Героическая фантастика
- Фэнтези
- Научная Фантастика
- Социально-психологическая
- Альтернативная история
- Боевая фантастика
- Разная литература
- Пословицы, поговорки
- Шахматы
- Визуальные искусства
- Фанфик
- Авто и ПДД
- Военное
- Отраслевые издания
- Гиды, путеводители
- Зарубежная образовательная литература
- Военная история
- Цитаты из афоризмов
- Современная литература
- Великолепные истории
- Начинающие авторы
- Современная зарубежная литература
- Боевые искусства
- Изобразительное искусство, фотография
- Кино
- Литература 19 века
- Недвижимость
- Музыка, музыканты
- Готические новеллы
- Истории из жизни
- Культура и искусство
- Спецслужбы
- Зарубежная прикладная литература
- Музыка, танцы
- Подростковая литература
- Прочее
- Военная техника, оружие
- Газеты и журналы
- Периодические издания
- Домоводство, Дом и семья
- Любовные романы
- Экономическая литература
- Научные и научно-популярные книги
- О животных
- Биохимия
- Культурология
- Юриспруденция
- Политика
- Психотерапия
- Языкознание
- Научпоп
- Медицина
- Психология, личное
- Радиотехника
- Филология
- Педагогика
- Образовательная литература
- Деловая литература
- Физика
- Науки: разное
- Химия
- Воспитание детей, педагогика
- Детская психология
- Зарубежная публицистика
- Биология
- Архитектура
- Зарубежная психология
- Науки о космосе
- Социология
- Математика
- География
- Беременность, ожидание детей
- Литературоведение
- Транспорт, военная техника
- Обществознание
- Зоология
- География
- Альтернативная медицина
- Иностранные языки
- Ветеринария
- Рефераты
- Астрология
- Биофизика
- Экология
- История Европы
- Учебники
- Шпаргалки
- Государство и право
- Ботаника
- Религиоведение
- История
- Техническая литература
- Прочая научная литература
- Психология
- Детективы и Триллеры
- Справочная литература
- Проза
- Новелла
- Юмор
- Проза
- Историческая проза
- Русская современная проза
- Советская классическая проза
- Повести
- Очерки
- Эссе
- Рассказы
- Зарубежная современная проза
- Сентиментальная проза
- Зарубежная классика
- Афоризмы
- Эпистолярная проза
- Феерия
- Семейный роман/Семейная сага
- Разное
- Антисоветская литература
- Магический реализм
- Русская классическая проза
- Современная проза
- О войне
- Контркультура
- Классическая проза
- Поэзия, Драматургия
- Детская литература
- Детская фантастика
- Детские остросюжетные
- Детские стихи
- Детские приключения
- Внеклассное чтение
- Учебная литература
- Зарубежные детские книги
- Бизнес
- Загадки
- Книги для подростков
- Школьные учебники
- Детский фольклор
- Книги для дошкольников
- Детские детективы
- Детская познавательная и развивающая литература
- Буквари
- Прочая детская литература
- Сказка
- Детская проза
- Детская образовательная литература
- Юмор
- Документальные книги
- Бизнес
- Внешнеэкономическая деятельность
- Тайм-менеджмент
- Кадровый менеджмент
- О бизнесе популярно
- Управление, подбор персонала
- Бизнес
- Менеджмент и кадры
- Продажи
- Экономика
- Ценные бумаги и инвестиции
- Малый бизнес
- Делопроизводство, офис
- Корпоративная культура, бизнес
- Банковское дело
- Финансы
- Зарубежная деловая литература
- Ораторское искусство / риторика
- Личные финансы
- Интернет-бизнес
- Поиск работы
- Государственное и муниципальное управление
- Бухучет и аудит
- Работа с клиентами
- Менеджмент
- Краткое содержание
- Личная эффективность
- Переговоры
- Приключения
- Старинная литература
- Религия и духовность
- Компьютеры и Интернет
- Блог
Читаем без скачивания C++17 STL Стандартная библиотека шаблонов - Яцек Галовиц
Шрифт:
Интервал:
Закладка:
Принимая это во внимание, можно нарисовать следующий DAG, который визуализирует зависимости между ними, что позволяет получить итоговый результат (рис. 9.4).
При реализации данной задачи в коде понятно, что все можно реализовать последовательно на одном ядре ЦП. Помимо этого, все подзадачи, которые не зависят от других подзадач или зависят от уже завершенных, могут быть выполнены конкурентно на нескольких ядрах ЦП.
Может показаться утомительным писать подобный код, даже с помощью std::async, поскольку зависимости между подзадачами нужно смоделировать. В этом примере мы реализуем две небольшие вспомогательные функции, которые позволяют преобразовать нормальные функции create, concat и twice в функции, работающие асинхронно. С их помощью мы найдем действительно элегантный способ создать граф зависимостей. Во время выполнения программы граф сам себя распараллелит, чтобы максимально быстро получить результат.
Как это делается
В этом примере мы реализуем некие функции, которые симулируют сложные для вычисления задачи, зависящие друг от друга, и попробуем максимально их распараллелить.
1. Сначала включим все необходимые заголовочные файлы и объявим пространство имен std:
#include <iostream>
#include <iomanip>
#include <thread>
#include <string>
#include <sstream>
#include <future>
using namespace std;
using namespace chrono_literals;
2. Нужно синхронизировать конкурентный доступ к cout, поэтому задействуем вспомогательный класс, который написали в предыдущей главе:
struct pcout : public stringstream {
static inline mutex cout_mutex;
~pcout() {
lock_guard<mutex> l {cout_mutex};
cout << rdbuf();
cout.flush();
}
};
3. Теперь реализуем три функции, которые преобразуют строки. Первая функция создаст объект типа std::string на основе строки, созданной в стиле C. Мы приостановим его на 3 секунды, чтобы симулировать сложность создания строки:
static string create(const char *s)
{
pcout{} << "3s CREATE " << quoted(s) << 'n';
this_thread::sleep_for(3s);
return {s};
}
4. Следующая функция принимает два строковых объекта и возвращает их сконкатенированный вариант. Мы будем приостанавливать ее на 5 секунд, чтобы симулировать сложность выполнения этой задачи:
static string concat(const string &a, const string &b)
{
pcout{} << "5s CONCAT "
<< quoted(a) << " "
<< quoted(b) << 'n';
this_thread::sleep_for(5s);
return a + b;
}
5. Последняя функция, наполненная вычислениями, принимает строку и конкатенирует ее с самой собой. На это потребуется 3 секунды:
static string twice(const string &s)
{
pcout{} << "3s TWICE " << quoted(s) << 'n';
this_thread::sleep_for(3s);
return s + s;
}
6. Теперь можно использовать эти функции в последовательной программе, но мы же хотим элегантно ее распараллелить! Так что реализуем некоторые вспомогательные функции. Будьте внимательны, следующие три функции выглядят действительно сложными. Функция asynchronize принимает функцию f и возвращает вызываемый объект, который захватывает ее. Можно вызвать данный объект, передав ему любое количество аргументов, и он захватит их вместе с функцией f в другой вызываемый объект, который будет возвращен. Этот последний вызываемый объект может быть вызван без аргументов. Затем он вызывает функцию f асинхронно со всеми захваченными им аргументами:
template <typename F>
static auto asynchronize(F f)
{
return [f](auto ... xs) {
return [=] () {
return async(launch::async, f, xs...);
};
};
}
7. Следующая функция будет использоваться функцией, которую мы объявим на шаге 8. Она принимает функцию f и захватывает ее в вызываемый объект; его и возвращает. Данный объект можно вызвать с несколькими объектами типа future. Затем он вызовет функцию .get() для всех этих объектов, применит к ним функцию f и вернет результат:
template <typename F>
static auto fut_unwrap(F f)
{
return [f](auto ... xs) {
return f(xs.get()...);
};
}
8. Последняя вспомогательная функция также принимает функцию f. Она возвращает вызываемый объект, который захватывает f. Такой вызываемый объект может быть вызван с любым количеством аргументов, представляющих собой вызываемые объекты, которые он возвращает вместе с f в другом вызываемом объекте. Этот итоговый вызываемый объект можно вызвать без аргументов. Он вызывает все вызываемые объекты, захваченные в наборе xs.... Они возвращают объекты типа future, которые нужно распаковать с помощью функции fut_unwrap. Распаковка объектов типа future и применение самой функции f для реальных значений, находящихся в объектах типа future, происходит асинхронно с помощью std::async:
template <typename F>
static auto async_adapter(F f)
{
return [f](auto ... xs) {
return [=] () {
return async(launch::async,
fut_unwrap(f), xs()...);
};
};
}
9. О’кей, возможно, предыдущие фрагменты кода были несколько запутанными и напоминали фильм «Начало» из-за лямбда-выражений, возвращающих лямбда-выражения. Мы подробно рассмотрим этот вуду-код далее. Теперь возьмем функции create, concat и twice и сделаем их асинхронными. Функция async_adapter заставляет обычную функцию ожидать получения аргументов типа future и возвращает в качестве результата объект типа future. Она похожа на оболочку, преобразующую синхронный мир в асинхронный. Необходимо использовать функцию asynchronize для функции create, поскольку она будет возвращать объект типа future, но следует передать ей реальные значения. Цепочка зависимостей для задач должна начинаться с вызовов create:
int main()
{
auto pcreate (asynchronize(create));
auto pconcat (async_adapter(concat));
auto ptwice (async_adapter(twice));
10. Теперь у нас есть функции, которые распараллеливаются автоматически и имеют такие же имена, что и оригинальные функции, но с префиксом p. Далее создадим сложное дерево зависимостей. Сначала добавим строки "foo " и "bar ", которые мгновенно сконкатенируем в "foo bar ". Эта строка будет сконкатенирована сама с собой с помощью функции twice. Затем создадим строки "this " и "that ", которые сконкатенируем в "this that ". Наконец, сконкатенируем все эти строки в "foo bar foo bar this that ". Результат будет сохранен в переменной