Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

лаб5 / lab5

.docx
Скачиваний:
10
Добавлен:
27.08.2024
Размер:
132.77 Кб
Скачать

ГУАП

КАФЕДРА № 41

ОТЧЕТ ЗАЩИЩЕН С ОЦЕНКОЙ

ПРЕПОДАВАТЕЛЬ

Старший преподаватель

Д.В. Куртяник

должность, уч. степень, звание

подпись, дата

инициалы, фамилия

ОТЧЕТ О ЛАБОРАТОРНОЙ РАБОТЕ 5

Параллелизм

по курсу: ОСНОВЫ ПРОГРАММИРОВАНИЯ

РАБОТУ ВЫПОЛНИЛ

СТУДЕНТ ГР. №

4016

М.О.Жовтяк

подпись, дата

инициалы, фамилия

Санкт-Петербург 2021

  1. Постановка задачи

Цель лабораторной работы: изучение автоматического распараллеливания кода, использующего стандартные алгоритмы библиотеки STL, способов применения и особенностей работы; получение навыков программирования на языке C++.

Задание на программирование: разработать программу и провести анализ эффективности работы с использованием различных политик распараллеливания и с использованием автоматического параллелизатора, автоматического векторизатора.

Мой индивидуальный вариант – 17. Сформировать коллекцию L, включив в неё по одному разу элементы, которые входят в коллекцию L1, но не входят в коллекцию L2.

  1. Математическая модель решения с указанием подходящих методов решения и алгоритмов из библиотеки 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)

  1. Сравнение эффективности выполнения

Числовые значения в ячейках фиксируют время с начала работы программы и измеряются в миллисекундах. Число элементов контейнера для заполнения равно одному миллиону.

Без авто параллелизации и авто векторизации

Vector 1

Vector 2

Vector

Без политики

2073

3965

10468

Политика “par”

1845

3701

9263

Политика “seq”

1980

3990

11169

Политика “par_unseq”

1895

3781

9422

С авто параллелизацией

Без политики

2132

4010

10777

Политика “par”

2134

4059

9566

Политика “seq”

2093

3859

10671

Политика “par_unseq”

1852

3635

9532

С авто векторизацией

Без политики

2027

4040

10744

Политика “par”

1939

3995

9173

Политика “seq”

2045

4272

10969

Политика “par_unseq”

1850

3627

9646

Таблица 1 – Скорость работы при разных настройках компилятора и политиках распараллеливания

Ссылаясь на табл. 1 можно сделать определённые выводы. Зеленым светом подсвечены значения, которые отличаются более быстрой скоростью работы. Скорость заполнения при всех политиках и при всех настройках компилятора примерно равны. Но при политиках “par” и “par_unseq” замечается рост скорости работы примерно на 1 секунду, что составляет сокращение времени работы на примерно 10%. Политика “seq” и без политичное распараллеливание показали худшие результаты. Особенно плохо показала себя политика “seq”, которая работает медленнее, чем при ситуации, когда политики нет. Стоит обратить внимание, что автоматическая параллелизация и векторизация немного, но ускоряют работы последних упомянутых политик.

  1. Скриншоты работы

На рисунке 1 продемонстрирована работа компилятора с миллионом значений. Вызов функций «showme» закомментирован. Такой способ был использован для сравнения скорости работы при различных политиках распараллеливания и настройках компилятора.

Рисунок 1 – Пример работы программы с миллионом элементов

Рисунок 2 – Демонстрация работы программы с малым количеством элементов

Рисунок 3 – Настройки компилятора

  1. Код программы

#include <iostream>

#include <vector>

#include <algorithm>

#include <iterator>

#include <ctime>

#include <execution>

#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);

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. Также я выяснил, что параллельное выполнение потоков помогает ускорить работу программы за счет распределения ресурсов ядер процессора компьютера, что делает и так быстрый язык С++ более быстрым.

Список используемых ресурсов

  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

Соседние файлы в папке лаб5