chitay-knigi.com » Разная литература » C++17 STL Стандартная библиотека шаблонов - Яцек Галовиц

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 93 94 95 96 97 98 99 100 101 ... 121
Перейти на страницу:
"bernoulli_distributionn";

  print_distro(std::bernoulli_distribution{0.75}, samples);

  cout << "discrete_distributionn";

  print_distro(discrete_distribution<int>{{1, 2, 4, 8}}, samples);

12. Существует множество других генераторов распределений. Они полезны только в очень специфических ситуациях. Если вы никогда о них не слышали, то они, возможно, вам и не нужны. Однако, поскольку наша программа создает «аккуратные» гистограммы, показывающие распределение, из интереса выведем их все:

  cout << "binomial_distributionn";

  print_distro(binomial_distribution<int>{10, 0.3}, samples);

  cout << "negative_binomial_distributionn";

  print_distro(negative_binomial_distribution<int>{10, 0.8}, samples);

  cout << "geometric_distributionn";

  print_distro(geometric_distribution<int>{0.4}, samples);

  cout << "exponential_distributionn";

  print_distro(exponential_distribution<double>{0.4}, samples);

  cout << "gamma_distributionn";

  print_distro(gamma_distribution<double>{1.5, 1.0}, samples);

  cout << "weibull_distributionn";

  print_distro(weibull_distribution<double>{1.5, 1.0}, samples);

  cout << "extreme_value_distributionn";

  print_distro(extreme_value_distribution<double>{0.0, 1.0}, samples);

  cout << "lognormal_distributionn";

  print_distro(lognormal_distribution<double>{0.5, 0.5}, samples);

  cout << "chi_squared_distributionn";

  print_distro(chi_squared_distribution<double>{1.0}, samples);

  cout << "cauchy_distributionn";

  print_distro(cauchy_distribution<double>{0.0, 0.1}, samples);

  cout << "fisher_f_distributionn";

  print_distro(fisher_f_distribution<double>{1.0, 1.0}, samples);

  cout << "student_t_distributionn";

  print_distro(student_t_distribution<double>{1.0}, samples);

}

13. Компиляция и запуск программы дадут следующий результат. Сначала запустим программу с 1000 образцами для каждого распределения (рис. 8.7).

14. Еще один запуск, на этот раз с 1 000 000 образцов для каждого распределения, покажет, что гистограммы выглядят гораздо чище и более характерно для каждого из них. Кроме того, мы увидим, какие распределения генерируются медленно, а какие — быстро (рис. 8.8).

Как это работает

Хотя генераторы случайных чисел нас не интересуют до тех пор, пока работают быстро и создают числа максимально случайным образом, нам следует тщательно выбирать распределение в зависимости от решаемой задачи.

Чтобы использовать любое распределение, сначала нужно создать для него соответствующий объект. Мы видели, что разные распределения принимают разные аргументы конструктора. В описании примера мы кратко остановились на некоторых видах распределения, поскольку большинство из них слишком специфичны и/или сложны, чтобы рассматривать их здесь. Не волнуйтесь, все они подробно описаны в документации к C++ STL.

Однако, как только появляется экземпляр распределения, можно вызвать его как функцию, которая принимает в качестве единственного параметра объект генератора случайных чисел. Далее объект распределения получает случайное число, придает ему некую форму (которая полностью зависит от выбранного распределения), а затем возвращает его нам. Это приводит к появлению совершенно разных гистограмм, что мы видели после запуска программы.

Программа, которую мы только что написали, позволит нам получить наиболее полную информацию о разных распределениях. В дополнение к этому рассмотрим самые важные виды распределения (табл. 8.2). Для всех остальных видов распределения вы можете обратиться к документации C++ STL.

Глава 9

Параллелизм и конкурентность 

В этой главе:

□ автоматическое распараллеливание кода, использующего стандартные алгоритмы;

□ приостановка программы на конкретный промежуток времени;

□ запуск и приостановка потоков;

□ выполнение устойчивой к исключениям общей блокировки с помощью std::unique_lock и std::shared_lock;

□ избегание взаимных блокировок с применением std::scoped_lock;

□ синхронизация конкурентного использования std::cout;

□ безопасное откладывание инициализации с помощью std::call_once;

□ отправка выполнения задач в фоновый режим с применением std::async;

□ реализация идиомы «производитель/потребитель» с использованием std::condition_variable;

□ реализация идиомы «несколько потребителей/производителей» с помощью std::condition_variable;

□ распараллеливание отрисовщика множества Мандельброта в ASCII с применением std::async;

□ реализация небольшой автоматической библиотеки для распараллеливания с использованием std::future. 

Введение

До C++11 язык C++ не поддерживал параллельные вычисления. Это не значило, что запуск, управление, остановка и синхронизация потоков были невыполнимы, но для каждой операционной системы требовались специальные библиотеки, поскольку потоки по своей природе связаны с ОС.

С появлением C++11 мы получили библиотеку std::thread, которая позволяет управлять потоками всех операционных систем. Для синхронизации потоков в C++11 были созданы классы-мьютексы, а также удобные оболочки блокировок в стиле RAII. Вдобавок std::condition_variable позволяет отправлять гибкие уведомления о событиях между потоками.

Кроме того, интересными дополнениями являются std::async и std::future: теперь можно оборачивать произвольные нормальные функции в вызовы std::async, чтобы выполнять их асинхронно в фоновом режиме. Такие обернутые функции возвращают объекты типа std::future, которые обещают содержать результаты работы функции, и можно сделать что-то еще, прежде чем дождаться их появления. Еще одно значительное улучшение STL — политики выполнения, которые могут быть добавлены к 69 уже существующим алгоритмам. Это дополнение означает, что можно просто добавить один аргумент, описывающий политику выполнения, в существующие вызовы стандартных алгоритмов и получить доступ к параллелизации, не нуждаясь в переписывании сложного кода.

В данной главе мы пройдемся по всем указанным дополнениям, чтобы узнать их самые важные особенности. После этого у нас будет достаточно информации о поддержке параллелизации в STL версии C++17. Мы не станем рассматривать все свойства, только самые важные. Информация, полученная из этой книги, позволит быстро понять остальную часть механизмов распараллеливания, которую можно найти в Интернете в документации к STL версии C++17.

Наконец, в этой главе содержатся два дополнительных примера. В одном из них мы распараллелим отрисовщик множества Мандельброта в ASCII из главы 6, внеся минимальные изменения. В последнем примере реализуем небольшую библиотеку, которая помогает распараллелить выполнение сложных задач неявно и автоматически. 

Автоматическое распараллеливание кода, использующего стандартные алгоритмы

В C++17 появилось одно действительно крупное расширение для параллелизма: политики выполнения для стандартных алгоритмов. Шестьдесят девять алгоритмов были расширены и теперь принимают политики выполнения, чтобы работать параллельно на нескольких ядрах и даже при включенной векторизации.

Для пользователя это значит следующее: если мы уже повсеместно задействуем алгоритмы STL, то можем параллелизовать их работу без особых усилий. Мы легко можем дополнить наши приложения параллелизацией, просто добавив один аргумент, описывающий политику выполнения, в существующие вызовы алгоритмов STL.

В данном разделе мы реализуем простую программу (с не самым серьезным сценарием применения), которая генерирует несколько вызовов алгоритмов STL. При этом увидим, как легко использовать политики выполнения C++17, чтобы запустить их в нескольких потоках. В последних подразделах мы более подробно рассмотрим разные политики выполнения.

Как это делается

В данном примере мы напишем программу, использующую некоторые стандартные алгоритмы. Сама программа является скорее примером того, как могут выглядеть реальные сценарии, а не средством решения настоящей рабочей проблемы. Применяя эти стандартные алгоритмы, мы встраиваем политики выполнения, чтобы ускорить выполнение кода.

1. Сначала включим некоторые заголовочные файлы и объявим об использовании пространства имен std.

1 ... 93 94 95 96 97 98 99 100 101 ... 121
Перейти на страницу:

Комментарии
Минимальная длина комментария - 25 символов.
Комментариев еще нет. Будьте первым.