
лаб5 / lab5
.pdf
ГУАП КАФЕДРА № 41
ОТЧЕТ ЗАЩИЩЕН С ОЦЕНКОЙ ПРЕПОДАВАТЕЛЬ
Старший преподаватель |
Д.В. Куртяник |
должность, уч. степень,
подпись, дата инициалы, фамилия
звание
ОТЧЕТ О ЛАБОРАТОРНОЙ РАБОТЕ 5
Параллелизм
по курсу: ОСНОВЫ ПРОГРАММИРОВАНИЯ
РАБОТУ ВЫПОЛНИЛ |
|
|
|
|
|
|
СТУДЕНТ ГР. |
4016 |
|
|
|
М.О.Жовтяк |
|
№ |
|
|
|
|
||
|
|
|
|
|
||
|
|
|
|
|
|
|
|
|
|
|
подпись, дата |
|
инициалы, фамилия |
|
|
Санкт-Петербург 2021 |
|
|
1)Постановка задачи
Цель лабораторной работы: изучение автоматического распараллеливания кода, использующего стандартные алгоритмы библиотеки STL, способов применения и особенностей работы; получение навыков программирования на языке C++.
Задание на программирование: разработать программу и провести анализ эффективности работы с использованием различных политик распараллеливания и с использованием автоматического параллелизатора, автоматического векторизатора.
Мой индивидуальный вариант – 17. Сформировать коллекцию L, включив в неё по одному разу элементы, которые входят в коллекцию L1, но не входят в коллекцию L2.
2) Математическая модель решения с указанием подходящих методов решения и алгоритмов из библиотеки STL
В качестве рабочего контейнера был выбран <vector>. Политиками execution
выбраны sequenced_policy (seq), parallel_policy (par), parallel_unseqeunced_policy(par_unseq). В настройках компилятора периодически будут настраиваться автоматическая параллелизация и векторизация.
Будут созданы шаблоны STL:
Заполняющий контейнер случайными числами;
Итерация контейнера;
Шаблон, выполняющий ключевую функцию задачи – заполнение основного контейнера элементами обоих векторов; сортировка всех элементов в нем; удаление повторяющихся элементов и элементов, входящих во второй контейнер.
Задача функции main() заключается в исполнении вызова функции-шаблона, передавая в качестве параметров вектора. Также в этой функции будет выполняться подсчет времени выполнения программы.
Политика параллелизма может быть применена только для функций sort и for_each, которые присутствуют в составленной программе.
Для данной задачи подойдут следующие методы и алгоритмы из библиотеки STL:
unique() – для удаление равных соседних элементов при сохранении первого
из них;
insert(p, x) – для добавления х перед элементом, на который указывает р;
end() – для указания на элемент, который следует за последним;
begin() – указывает на первый элемент;
find – для нахождения итератора на элемент и проверки на его существование;
count – для возвращения количества элементов с заданным значением;
erase – для удаление конкретного элемента.
remove – удаление элемента с определенным значением
for_each – применяет заданный функциональный объект к результату разыменования каждого итератора в диапазоне [first, last)
2
3)Сравнение эффективности выполнения
Числовые значения в ячейках фиксируют время с начала работы программы и измеряются в миллисекундах. Число элементов контейнера для заполнения равно одному миллиону.
|
|
|
|
|
|
|
Без |
авто параллелизации и авто векторизации |
|||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Vector |
1 |
Vector 2 |
|
Vector |
||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Без политики |
2073 |
|
3965 |
|
10468 |
||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Политика “par” |
|
1845 |
|
3701 |
|
|
9263 |
|
|||
|
|
|
|
|
|
|
|
|
|
|
|||
|
|
Политика “seq” |
1980 |
|
3990 |
|
11169 |
||||||
|
|
|
|
|
|
|
|
|
|
|
|||
|
|
|
Политика |
|
1895 |
|
3781 |
|
|
9422 |
|
||
|
“par_unseq” |
|
|
|
|
|
|
|
|
||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
С авто параллелизацией |
|
|
|
|
|
|
|
|
|
|
|
|
||||||
|
|
Без политики |
2132 |
|
4010 |
|
10777 |
||||||
|
|
|
|
|
|
|
|
|
|||||
|
|
Политика “par” |
|
2134 |
|
4059 |
|
|
9566 |
|
|||
|
|
|
|
|
|
|
|
||||||
|
|
Политика “seq” |
2093 |
|
3859 |
|
10671 |
||||||
|
|
|
|
|
|
|
|
|
|
||||
|
|
|
Политика |
|
1852 |
|
3635 |
|
|
9532 |
|
||
|
“par_unseq” |
|
|
|
|
|
|
|
|
||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
С авто векторизацией |
|
|
|
|
|
|
|
|
|
|
|
|
||||||
|
|
Без политики |
2027 |
|
4040 |
|
10744 |
||||||
|
|
|
|
|
|
|
|
|
|||||
|
|
Политика “par” |
|
1939 |
|
3995 |
|
|
9173 |
|
|||
|
|
|
|
|
|
|
|
||||||
|
|
Политика “seq” |
2045 |
|
4272 |
|
10969 |
||||||
|
|
|
|
|
|
|
|
|
|
||||
|
|
|
Политика |
|
1850 |
|
3627 |
|
|
9646 |
|
||
|
“par_unseq” |
|
|
|
|
|
|
|
|
||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Таблица 1 – Скорость работы при разных настройках компилятора и политиках распараллеливания
Ссылаясь на табл. 1 можно сделать определённые выводы. Зеленым светом подсвечены значения, которые отличаются более быстрой скоростью работы. Скорость заполнения при всех политиках и при всех настройках компилятора примерно равны. Но при политиках “par” и “par_unseq” замечается рост скорости работы примерно на 1 секунду, что составляет сокращение времени работы на примерно 10%. Политика “seq” и без политичное распараллеливание показали худшие результаты. Особенно плохо показала себя политика “seq”, которая работает медленнее, чем при ситуации, когда политики нет. Стоит обратить внимание, что автоматическая параллелизация и векторизация немного, но ускоряют работы последних упомянутых политик.
3

4)Скриншоты работы
На рисунке 1 продемонстрирована работа компилятора с миллионом значений. Вызов функций «showme» закомментирован. Такой способ был использован для сравнения скорости работы при различных политиках распараллеливания и настройках компилятора.
Рисунок 1 – Пример работы программы с миллионом элементов
Рисунок 2 – Демонстрация работы программы с малым количеством элементов
Рисунок 3 – Настройки компилятора
5) Код программы
#include <iostream> #include <vector> #include <algorithm> #include <iterator> #include <ctime> #include <execution>
4
#include <thread> using namespace std;
//заполение вектора
template <typename container>
int filling(container& con, int number)
{
int start = clock();
#pragma loop(hint_parallel(8)); for (int i = 0; i < number; i++)
{
int element = rand() % 1001; con.insert(con.end(), element); element = 0;
}
int end = clock(); return (end - start);
}; //отображение вектора
template <typename container> void showme(container con)
{
cout << "Content of container:";
for_each(con.begin(), con.end(), [](auto a) {std::cout << a << " "; }); std::cout << "completed" << std::endl;
}
//выполнение задачи
template <typename container>
void del(container& con1, container& con2, container& con)
{
vector<int>::iterator it1;
for (it1 = con1.begin(); it1 != con1.end(); ++it1) con.push_back(*it1);
//сортировка и удаление одинаковых элементов коллекции L для более легкого
восприятия
sort(con.begin(), con.end());
auto last1 = unique(con.begin(), con.end()); con.erase(last1, con.end());
//уничтожение элементов L, которые входят в коллекцию L2 for (it1 = con2.begin(); it1 != con2.end(); ++it1)
{
con.erase(remove(con.begin(), con.end(), *it1), con.end());
}
}
int main()
{
int edro = std::thread::hardware_concurrency();
std::cout <<"There are " << edro << " concurrent supported threads.\n"; cout << "Enter number of values for container" << endl;
int number; cin >> number;
vector<int> vect1; vector<int> vect2; vector<int> vect; int time = 0;
time += filling(vect1, number); showme(vect1);
cout << "Spent time for now: " << time << endl; time += filling(vect2, number);
5
showme(vect2);
cout << "Spent time for now: " << time << endl; int start = clock();
del(vect1, vect2, vect); showme(vect);
int end = clock(); time += (end - start);
cout << "Spent time: " << time << endl; cout << endl;
}
Вывод: Политики “par” и “par_unseq” ускорили работу программы, особенно при сортировке элементов при выполнении задачи, остальные не принесли ожидаемых результатов. В ходе работы я познакомился с такими понятиями, как распараллеливания кода, закрепил знания по алгоритмам STL. Также я выяснил, что параллельное выполнение потоков помогает ускорить работу программы за счет распределения ресурсов ядер процессора компьютера, что делает и так быстрый язык С++ более быстрым.
6
Список используемых ресурсов
1)https://pro.guap.ru/get-task/74c98e96d0cef0464bf8271a428c8a14
2)https://docs.microsoft.com/ru-ru/cpp/parallel/auto-parallelization-and-auto- vectorization?view=msvc-160#auto-vectorizer
7