Сравнение эффективности алгоритмов 


Мы поможем в написании ваших работ!



ЗНАЕТЕ ЛИ ВЫ?

Сравнение эффективности алгоритмов



В 1 главе был приведён пример ситуации, когда период обработки Greedy-Balance алгоритма превышал период обработки Sorted-Balance почти в два раза. На практике такая ситуация является исключительной и маловероятной. Для сравнения эффективности алгоритмов будут сгенерированы следующие файлы: количество машин равно 1000, количество задач будет равно 2000, 5000 и 10000. Время выполнения задания будут варьироваться в пределах: от 1 до 50, от 30 до 50, от 50 до 90. Всего будут сгенерированы данные для 1000 тестов. В Таблице 3 представлено сравнение периодов обработки Greedy-Balance и Sorted-Balance алгоритмов.

Таблица 3. Сравнение периодов обработки.

     
Количество задач Минимальное время выполнения Максимальное время выполнения Максимальный % Минимальный % Средний %
2000 1 50 69% 54% 62%
5000 1 50 24% 19% 21%
10000 1 50 13% 11% 12%
2000 30 50 25% 21% 24%
5000 30 50 14% 12% 13%
10000 30 50 8% 6% 7%
2000 50 90 29% 24% 27%
5000 50 90 15% 12% 14%
10000 50 90 8% 7% 7%

В первом столбце указано количество задач, участвующий в распределении. Во втором столбце указано минимальное время выполнения одного задания. В третьем столбце указано максимальное время выполнения одного задания. В последующих столбцах указано максимальное, минимальное и среднее значение отношения периода обработки Greedy-Balance и периода обработки Sorted-Balance. Процент вычисляется как: , где P – период обработки. Данный процент показывает, насколько период обработки Greedy-Balance больше периода обработки Sorted-Balance.

По результатам тестирований, с увеличением количества задач, которых необходимо распределить между машинами, разрыв периодов обработки алгоритмов сокращается. Также на сокращение разрыва влияет промежуток между минимальным и максимальным временем выполнения. Чем меньше промежуток, тем меньше разница между Greedy-Balance и Sorted-Balance алгоритмами. Таким образом, используя Greedy-Balance в системе с большим количество задач и малым промежутком между временем выполнения задач, можно добиться получения очень близкого к Sorted-Balance результата.

Выводы по главе

Жадные алгоритмы балансировки несложные в реализации. В них используются простые структуры данных, которые можно реализовать на большинстве языков программирования. В то же время, данные алгоритмы нужно использовать в зависимости от количества машин и входящих задач. При небольшом количестве машин применение обычного перебора для поиска машины с минимальной нагрузкой будет оптимальным вариантов, иначе лучше использовать модификации жадных алгоритмов с очередью с приоритетом. При использовании жадных алгоритмов с применением сортировки необходимо учитывать временную сложность её выполнения.  С возрастанием количества задач время выполнения такой балансировки начинает увеличиваться. Когда количество задач в несколько раз больше, чем количество машин, и задачи имеют близкое друг к другу время выполнения, использование Greedy-Balance выдаст приближённый к Sorted-Balance результат.


 

Заключение

На сегодняшний день существует большое количество методов балансировки нагрузки. К таким методам также относится применение жадных алгоритмов. Данные алгоритмы на каждом шаге работы выбирают наилучший вариант, чтобы получить в итоге оптимальный результат. Greedy-Balance алгоритм строит решение с периодом обработки  за O (Log(M) · N), в то время как Sorted-Balance строит решение с периодом обработки  за O ( + Log(M) · N). Эти алгоритмы имеют простую реализацию и могут быть разработаны на большом количестве языков программирования и использоваться в большинстве систем. В системах, в которых используется небольшое количество серверов, использование жадных алгоритмов без очереди с приоритетом будет оптимальным. Если же используется несколько сотен или тысяч серверов, то в жадных алгоритмах балансировки необходимо использовать очередь с приоритетом, так как это снизит время работы в несколько раз. Количество поступаемых задач влияет на результат балансировки алгоритмов. С возрастанием их количества разрыв в периоде обработки между Greedy-Balance и Sorted-Balance сокращается. Кроме того, если количество задач меньше количества машин, то периоды обработки алгоритмов будут одинаковые, но Sorted-Balance будет работать дольше из-за выполнения сортировки. Таким образом, применение в балансировке Greedy-Balance алгоритма будет эффективным при количестве задач меньше количества машин, либо количество задач в несколько раз больше количества машин. Вдобавок, этот алгоритм будет эффективен при условии, когда время выполнения задач близко друг к другу. В остальных случаях алгоритм Sorted-Balance выдаст лучший результат.


 

Библиографический список

1. Arregoces M., Portolani M. Data Center Fundamentals. – Cisco Press, 2004. – p. 676 –681.

2. KEMP Technologies: Load Balancing Techniques and Algorithms. [Электронный ресурс] – Режим доступа: https://kemptechnologies.com/load-balancer/load-balancing-algorithms-techniques/.

3. Клейнберг Дж., Тардос Е. Алгоритмы: разработка и применение. Классика Computers Science. – СПб.: Питер, 2016. – с. 600–605.

4. Кормен Т., Лейзерсон Ч., Ривест Р., Штайн К. Алгоритмы: Построение и анализ. – М.: И. Д. Вильямс, 2013. – с. 448.

5. Куроуз Д., Росс К. Компьютерные сети: Нисходящий подход. – М.: Издательство «Э», 2016. – с. 555.


 

Приложения

Приложение 1

AlgorithmTester.cpp:

#include "stdafx.h"

#include "Balancer.h"

#include <fstream>

#include <string>

#include <ctime>

 

using namespace std;

 

void startTesting(string & testName); // функция тестирования алгоритмов

 

int main() // главная функция

{

  system("chcp 1251"); // установка в консоли русского языка

  std::ios::sync_with_stdio(false); // отключение синхронизации с stdio для более быстрого чтения из файла

  string testName; // название файла для чтения

  cout << "Введите название теста, который будет выполняться" << endl; // вывод текста в консоль

  cin >> testName; // чтение из консоли названия файла

  startTesting(testName); // вызов функции тестирования алгоритмов

  cin.ignore(); // ожидание нажатий клавиш пользователем после выполнения тестов

  cin.get();

return 0;

}

 

void startTesting(string & testName)

{

  int numberOfMachines, numberOfTasks, numberOfTests; // numberOfMachines - число машин, numberOfTasks - число задач, numberOfTests - число тестов

  ifstream input("../Tests/" + testName + ".txt"); // открываем файл для чтения из него тестов и заданий

  clock_t operatingTime[4] = { 0 }; // объявляем массив с временем выполнения всех тестов для каждого алгоритма

  if (!input.is_open()) // если не получается открыть файл, выходим из функции

  {

        cout << "Невозможно открыть файлы тестирования" << endl;

        input.close(); // закрытие файла

        return; // выход из функции

  }

  input >> numberOfTests >> numberOfMachines >> numberOfTasks; // считываем из файла информацию

  cout << "Начато тестирование: " << testName << endl;

  cout << "Число машин: " << numberOfMachines << endl;

  cout << "Число задач в 1 тесте: " << numberOfTasks << endl;

  cout << "Общее число тестов: " << numberOfTests << endl;

  ofstream result("../Tests/result_" + testName + ".txt"); // создаем файл result.txt для вывода информации

  for (int i = 1; i <= numberOfTests; i++) // в цикле от 1 до числа тестов выполняем тестирование алгоритмов

  {

        int taskTime, workTime; // taskTime - время выполнения задания, workTime - время выполнения балансировки

        Balancer greedyTests[4]; // создаём объекты класса

        clock_t startTime, finishTime; // startTime - время начала выполнения балансировки

        for (int task = 0; task < numberOfTasks; task++) // считываем numberOfTasks чисел из файла и добавляем их в балансировщики

        {

               input >> taskTime; // считываем из текстового файла время выполнения задания

               for (int j = 0; j < 4; j++)

                      greedyTests[j].addTask(taskTime); // добавляем в каждый балансировщик данное задание

        }

        for (int j = 0; j < 4; j++) // выполнение тестирования

        {

               greedyTests[j].setNumberOfMachines(numberOfMachines); // устанавливаем количество машин в балансировщике

               startTime = clock(); // получаем время начала работы алгоритма

               greedyTests[j].startBalancing(j); // запускаем балансировку с необходимым алгоритмом

               finishTime = clock(); // получаем время после работы алгоритма

               workTime = (finishTime - startTime); // вычисляем время выполнения

               operatingTime[j] += workTime; // прибавляем время к общему времени

               result << greedyTests[j].getProcessingPeriod() << "\t" << (double)workTime /1000.0 << "\t"; // вывод в файл периода обработки

        }

        result << endl; // переход в файле на следующую строку

  }

  for (int j = 0; j < 4; j++)

        result << "\t" << (double)operatingTime[j] / 1000.0 << "\t"; // вывод в файл времени выполнения всех тестов

  cout << "Тестирование завершено" << endl;

  result.close(); // закрытие файлов

  input.close();

}

Balancer.h:

#pragma once

class Balancer

{

private:

  struct Task {

        int id = 0, processingTime = 0;

  }; // структура, содержащая информацию о задаче. id - номер задачи, processingTime - время выполнения

 

  struct Machine {

        int totalTime = 0, id = 0;

        std::vector<Task> assignedTasks;

  }; // структура, содержащая информацию о машине. totalTime - сумма времени выполнения всех задач, id - номер машины

  // assignedTasks - множество поставленных задач

 

  std::vector<Task> sortedTasks; // множество задач для алгоритмов с сортировкой

  std::queue<Task> tasks; // множество задач для алгоритмов без сортировки

  std::vector<Machine> machines; // множество машин

  std::vector<int> priorityList; // список для очереди с приоритетом

  int numberOfTasks, numberOfMachines; // numberOfTasks - число задач, numberOfMachines - число машин

 

  static bool compareMachines(const Machine &a, const Machine &b); // функция сравнения двух машин

  static bool compareTasks(const Task &a, const Task &b); // функция сравнения двух задач

  void updateQueue(); // функция обновления очереди с приоритетом

public:

  Balancer(); // конструктор класса

  ~Balancer(); // деконструктор класса

 

  void addTask(int _processingTime); // функция добавления задачи

  void setNumberOfMachines(int numberOfMachines_); // функция установки балансировщику числа машин

  void greedyBalance(); // функция Greedy Balance алгоритма

  void sortedBalance(); // функция Sorted Balance алгоритма

  void greedyBalanceModified(); // функция Greedy Balance алгоритма с очередью с приоритетом

  void sortedBalanceModified(); // функция Sorted Balance алгоритма с использованием очереди с приоритетом

  int getProcessingPeriod(); // функция получения периода обработки

  void startBalancing(int type = 0); // функция запуска балансировки с указанным алгоритмом

};

 

Balancer.cpp:

#include "stdafx.h"

#include "Balancer.h"

 

bool Balancer::compareMachines(const Machine & a, const Machine & b)

{

  return a.totalTime < b.totalTime; // если время работы машины 'a' меньше времени работы машины 'b', то возвращается истина, иначе возвращается ложь

}

 

bool Balancer::compareTasks(const Task & a, const Task & b)

{

  return a.processingTime < b.processingTime; // если время выполнения задачи 'a' меньше времени выполнения задачи 'b', то возвращается истина, иначе возвращается ложь

}

 

void Balancer::updateQueue()

{

  int index = 0, left, right, min; // index - текущая вершина, left - левый потомок вершины, right - правый потомок вершины, min - индекс машины с минимальной нагрузкой

  while (true)

  {

        left = 2 * index + 1; // вычисляем левого потомка

        right = 2 * index + 2; // вычисляем правого потомка

        min = index; // присваиваем минимальному индексу текущий индекс

        if (left < numberOfMachines && machines[priorityList[left]].totalTime < machines[priorityList[min]].totalTime)

               min = left; // если левый потомок имеет меньшую нагрузку, то он становится минимальным

        if (right < numberOfMachines && machines[priorityList[right]].totalTime < machines[priorityList[min]].totalTime)

               min = right; // если правый потомок имеет меньшую нагрузку, то он становится минимальным

        if (index == min) return; // если минимальный индекс не изменился, то выходим из функции

        std::swap(priorityList[min], priorityList[index]); // поднимаем на вершину минимальным элемент

        index = min; // текущий индекс становится равен минимальному

  }

}

 

Balancer::Balancer()

{

  numberOfTasks = 0; // количество задач равно 0

  numberOfMachines = 0; // количество машин равно 0

}

 

Balancer::~Balancer()

{

}

 

void Balancer::addTask(int _processingTime)

{

  Task task; // создаём задание

  task.id = ++numberOfTasks; // устанавливаем заданию номер

  task.processingTime = _processingTime; // устанавливаем заданию время выполнения

  tasks.push(task); // добавляем задание в конец множества задач

  sortedTasks.push_back(task); // добавляем задание в конец множества задач для алгоритмов с сортировкой

}

 

void Balancer::setNumberOfMachines(int numberOfMachines_)

{

  numberOfMachines = 0; // обнуление количества машин

  machines.resize(numberOfMachines_); // изменяем размер множества машин

  priorityList.resize(numberOfMachines_); // изменяем размер очереди с приоритетом

  for (std::vector<Machine>::iterator i = machines.begin(); i!= machines.end(); i++) // перебираем все машины

  {

        priorityList[numberOfMachines] = numberOfMachines; // добавляем машину в очередь с приоритетом

        (*i).id = ++numberOfMachines; // обновляем номер машины

  }

}

 

void Balancer::greedyBalance()

{

  while (!tasks.empty()) // пока множество задач не пустое

  {

        std::vector<Machine>::iterator min = std::min_element(machines.begin(), machines.end(), compareMachines); // находим машину с минимальной нагрузкой

        Task temp = tasks.front(); // получаем задание из множества задач

        (*min).assignedTasks.push_back(temp); // присваиваем задание машине

        (*min).totalTime += temp.processingTime; // прибавляем время выполнения задания к времени работы машины

        tasks.pop(); // удаляем задание из множества задач

  }

}

 

 

void Balancer::sortedBalance()

{

  std::sort(sortedTasks.begin(), sortedTasks.end(), compareTasks); // сортируем множество задач в порядке возрастания времени выполнения

  while (!sortedTasks.empty()) // пока множество задач не пустое

  {

        std::vector<Machine>::iterator min = std::min_element(machines.begin(), machines.end(), compareMachines); // находим машину с минимальной нагрузкой

        Task temp = sortedTasks.back(); // получаем с конца задание из множества задач

        (*min).assignedTasks.push_back(temp); // присваиваем задание машине

        (*min).totalTime += temp.processingTime; // прибавляем время выполнения задания к времени работы машины

        sortedTasks.pop_back(); // удаляем задание из множества задач

  }

}

 

void Balancer::greedyBalanceModified()

{

  while (!tasks.empty()) // пока множество задач не пустое

  {

        int min = priorityList[0]; // берём индекс машины с минимальной нагрузкой из очереди с приоритетом

        Task temp = tasks.front(); // берём задание из множества

        machines[min].assignedTasks.push_back(temp); // добавляем задание в множество задач машины

        machines[min].totalTime += temp.processingTime; // прибавляем время выполнения задания

        tasks.pop(); // убираем задание из множества

        updateQueue(); // обновляем очередь с приоритетом

  }

}

 

void Balancer::sortedBalanceModified()

{

  std::sort(sortedTasks.begin(), sortedTasks.end(), compareTasks); // сортируем множество задач в порядке возрастания времени выполнения

  while (!sortedTasks.empty()) // пока множество задач не пустое

  {

        int min = priorityList[0]; // берём индекс машины с минимальной нагрузкой из очереди с приоритетом

        Task temp = sortedTasks.back(); // берём задание из множества

        machines[min].assignedTasks.push_back(temp); // добавляем задание в множество задач машины

        machines[min].totalTime += temp.processingTime; // прибавляем время выполнения задания

        sortedTasks.pop_back(); // убираем задание из множества

        updateQueue(); // обновляем очередь с приоритетом

  }

}

 

int Balancer::getProcessingPeriod()

{

  int result = 0; // обнуляем результат

  for (std::vector<Machine>::iterator i = machines.begin(); i!= machines.end(); i++) // перебираем все машины

        if (i->totalTime > result) // если время работы машины больше, чем текущее значение, то обновляем текущее значение

               result = i->totalTime;

  return result;

}

 

void Balancer::startBalancing(int type)

{

  switch (type)

  {

  case 0: greedyBalance(); // если тип равен 0, то вызываем greedyBalance

        break;

  case 1: sortedBalance(); // если тип равен 1, то вызываем sortedBalance

        break;

  case 2: greedyBalanceModified(); // если тип равен 2, то вызываем greedyBalanceModified;

        break;

  case 3: sortedBalanceModified(); // если тип равен 3, то вызываем sortedBalanceModified

        break;

  }

}

Приложение 2

Тест №1

Список задач: 7 27 14 2 22 19 3 21 12 20

Greedy Balance

Время выполнения

Sorted Balance

Время выполнения

Машина

Назначенные задачи

Машина

Назначенные задачи

1

7

3

21

31

1

27

2

 

29

2

27

 

 

27

2

22

3

 

25

3

14

12

 

26

3

21

7

 

28

4

2

19

20

41

4

20

12

 

32

5

22

 

 

22

5

19

14

 

33

Тест №2

Список задач: 9 19 24 23 9 13 6 27 27 28

Greedy Balance

Время выполнения

Sorted Balance

Время выполнения

Машина

Назначенные задачи

Машина

Назначенные задачи

1

9

13

28

50

1

28

6

 

34

2

19

27

 

46

2

27

9

 

36

3

24

 

 

24

3

27

9

 

36

4

23

 

 

23

4

24

13

 

37

5

9

6

27

42

5

23

19

 

42

Тест №3

Список задач: 28 8 4 22 3 9 1 9 12 17

Greedy Balance

Время выполнения

Sorted Balance

Время выполнения

Машина

Назначенные задачи

Машина

Назначенные задачи

1

28

 

 

28

1

28

 

 

28

2

8

12

 

20

2

22

1

 

23

3

4

1

9

14

3

17

4

3

24

4

22

 

 

22

4

12

8

 

20

5

3

9

17

29

5

9

9

 

18

Тест №4

Список задач: 1 14 10 12 19 23 5 15 7 24

Greedy Balance

Время выполнения

Sorted Balance

Время выполнения

Машина

Назначенные задачи

Машина

Назначенные задачи

1

1

23

 

24

1

24

1

 

25

2

14

7

 

21

2

23

5

 

28

3

10

5

24

39

3

19

7

 

26

4

12

15

 

27

4

15

10

 

25

5

19

 

 

19

5

14

12

 

26

 

Тест №5

Список задач: 8 23 15 30 11 3 26 17 25 13

Greedy Balance

Время выполнения

Sorted Balance

Время выполнения

Машина

Назначенные задачи

Машина

Назначенные задачи

1

8

3

26

37

1

30

3

 

33

2

23

13

 

36

2

26

8

 

34

3

15

25

 

40

3

25

11

 

36

4

30

 

 

30

4

23

13

 

36

5

11

17

 

28

5

17

15

 

32


[1] Источник: http://www.internetworldstats.com/top20.htm

[2] Информация указана на официальном сайте: https://vk.com/about

[3] Источник: https://vk.com/dev/health



Поделиться:


Последнее изменение этой страницы: 2021-07-18; просмотров: 43; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 3.144.189.177 (0.354 с.)