Цель работы – получить представления о возможности библиотеки CCR для организации параллельных вычислений.

Задание на лабораторную работу:

1) разработайте последовательный алгоритм, решающий одну из приведённых ниже задач в соответствии с выданным вариантом задания;

2) разработайте параллельный алгоритм соответствующий варианту последовательного алгоритма;

3) выполните сравнение времени выполнения последовательного и параллельного алгоритмов обработки данных при различных размерностях исходных данных.

Задание: Разработать алгоритм сортировки массива

Для решения задачи сортировки эти три этапа выглядят так:

Сортируемый массив разбивается на две половины меньшего размера Каждая из получившихся половин сортируется отдельно любым алгоритмом. Два упорядоченных массива половинного размера соединяются в один.

Листинг

using System;

using System. Collections;

using System. Diagnostics;

using System. Threading;

using System. Collections. Generic;

using ponentModel;

using Microsoft. Ccr. Core;

using Microsoft. Dss. Core. Attributes;

using Microsoft. Dss. ServiceModel. Dssp;

using Microsoft. Dss. ServiceModel. DsspServiceBase;

using W3C. Soap;

using submgr =Microsoft. Dss. bscriptionManager;

namespace labwork11

{

  [Contract(Contract. Identifier)]

  [DisplayName("labwork11")]

  [Description("labwork11 service (no description provided)")]

  class labwork11Service : DsspServiceBase

  {

  /// <summary>

  /// Service state

НЕ нашли? Не то? Что вы ищете?

  /// </summary>

  [ServiceState]

  labwork11State _state = new labwork11State();

  /// <summary>

  /// Main service port

  /// </summary>

  [ServicePort("/labwork11", AllowMultipleInstances = true)]

  labwork11Operations _mainPort = new labwork11Operations();

  [SubscriptionManagerPartner]

  bscriptionManagerPort _submgrPort = new bscriptionManagerPort();

  /// <summary>

  /// Service constructor

  /// </summary>

  ///

  public labwork11Service(DsspServiceCreationPort creationPort)

  : base(creationPort)

  {

  }

  /// <summary>

  /// Service start

  /// </summary>

  ///

protected override void Start()

  {

  //

  // Add service specific initialization here

  //

  base. Start();

  Console. WriteLine("Последовательный алгоритм");

  //Здесь были типа глобальные переменные

  Global. k = 20000;

  Global. nc = 2; // число ядер

  Global. m = Global. k / Global. nc; //

  Global. s = Global. k / Global. nc;

  Global. A = new int[Global. k];

  // заполнение массива

  Random r = new Random();

  for (int i = 0; i < Global. k; i++)

  Global. A[i] = r. Next(100);

  //последовательный алгоритм

  Stopwatch sWatch = new Stopwatch();

  sWatch. Start();

  int step11 = 0;

  for (int ii = 0; ii < Global. nc; ii++)

  {

  for (int i = 0+step11; i < Global. k / Global. nc+step11; i++)

  for (int j = 0+step11; j < (Global. k / Global. nc+step11 - i - 1) ; j++)

  if (Global. A[j] > Global. A[j + 1])

  {

  int tmp;

  tmp = Global. A[j];

  Global. A[j] = Global. A[j + 1];

  Global. A[j + 1] = tmp;

  }

  step11 =ii*Global. k / Global. nc;

  }

  sWatch. Stop();

  Console. WriteLine(" Последовательный алгоритм= {0} .", sWatch. ElapsedMilliseconds. ToString());

  for (int i = 0; i < Global. k; i++)

  for (int j = 0; j < Global. k - i-1; j++)

  if (Global. A[j] > Global. A[j + 1])

  {

  int tmp;

  tmp = Global. A[j];

  Global. A[j] = Global. A[j + 1];

  Global. A[j + 1] = tmp;

  }

  Console. WriteLine("Выборка для котроля");

  foreach (int number in PrintArray(5,Global. A))

  {

  Console. Write(number. ToString() + " ");

  }

  ////////////////////////////////////////////////////////////////////// параллельный алгоритм

  Console. WriteLine("Конец последовательного алоритма");

  Console. WriteLine("Параллельный алгоритм");

  // создание массива объектов для хранения параметров

  InputData[] ClArr = new InputData[Global. nc];

  for (int i = 0; i < Global. nc; i++)

  ClArr[i] = new InputData();

  // делим количество элементов на nc частей

  int step = (Int32)(Global. k / Global. nc);

  // заполняем массив параметров

  int c = -1;

  for (int i = 0; i < Global. nc; i++)

  {

  ClArr[i].start = c + 1;

  ClArr[i].stop = c + step;

  c = c + step;

  for (int j = ClArr[i].start; j < ClArr[i].stop - 1; j++)

  {

  int kkk = 0;

  ClArr[i].B[kkk] = Global. A[j];

  kkk++;

  }

  }

  Dispatcher d = new Dispatcher(Global. nc, "Test Pool");

  DispatcherQueue dq = new DispatcherQueue("Test Queue", d);

  Port<int> p = new Port<int>();

  for (int i = 0; i < Global. nc; i++)

  Arbiter. Activate(dq, new Task<InputData, Port<int>>(ClArr[i], p, Mul));

  Arbiter. Activate(Environment. TaskQueue, Arbiter. MultipleItemReceive(true, p, 2,

  delegate(int[] array)

  {

  for (int i = 0; i < Global. nc; i++)

  {

  for (int j = ClArr[i].start; j < ClArr[i].stop - 1; j++)

  {

  int kkk = 0;

  Global. A[j] = ClArr[i].B[kkk];

  kkk++;

  }

  }

  }));

  Console. WriteLine("Реализация итераторов");

  InputData1[] ClArr1 = new InputData1[Global. nc];

  for (int i = 0; i < Global. nc; i++)

  ClArr1[i] = new InputData1();

  // делим количество элементов на nc частей

  int step1 = (Int32)(Global. k / Global. nc);

  // заполняем массив параметров

  int c1 = -1;

  for (int i = 0; i < Global. nc; i++)

  {

  ClArr1[i].start = c1 + 1;

  ClArr1[i].stop = c1 + step1;

  c1 = c1 + step1;

  for (int j = ClArr1[i].start; j < ClArr1[i].stop-1; j++)

  {

  int kkk = 0;

  ClArr1[i].B[kkk] = Global. A[j];

  kkk++;

  }

  }

  Dispatcher Disp = new Dispatcher(Global. nc, "Test Pool");

  DispatcherQueue taskQ = new DispatcherQueue("Test Queue", Disp);

  Port<int> p1 = new Port<int>();

  Console. WriteLine("Before Iterator submitted - thread {0}", Thread. CurrentThread. ManagedThreadId);

  for (int i = 0; i < Global. nc; i++)

  {

  Arbiter. ExecuteToCompletion(taskQ, new IterativeTask<Port<int>, InputData1>(p1, ClArr1[i], IteratorExample));

  }

  Arbiter. MultipleItemReceive(false, p1, 2 , delegate(int[] array)

  {

  for (int i = 0; i < Global. nc; i++)

  {

  for (int j = ClArr[i].start; j < ClArr[i].stop - 1; j++)

  {

  int kkk = 0;

  Global. A[j] = ClArr[i].B[kkk];

  kkk++;

  }

  }

  Console. WriteLine("Вычисления окончены");

  });

  Console. WriteLine("After Iterator submitted - thread {0}", Thread. CurrentThread. ManagedThreadId);

  }

  /// <summary>

  /// Handles Subscribe messages

  /// </summary>

  /// <param name="subscribe">the subscribe request</param>

  [ServiceHandler]

  public void SubscribeHandler(Subscribe subscribe)

  {

  SubscribeHelper(_submgrPort, subscribe. Body, subscribe. ResponsePort);

  }

  public class InputData

  {

  public int start;  //Начало диапазона

  public int stop;  //Конец диапазона

  public int[] B = new int[Global. k / Global. nc];

  }

  public class InputData1

  {

  public int start;  //Начало диапазона

  public int stop;

  //Конец диапазона

  public int[] B = new int[Global. k / Global. nc];

  }

  public static System. Collections. Generic. IEnumerable<int>

  PrintArray(int firstNumber, int[] arr)

{

  // Yield even numbers in the range.

  for (int number = 0; number < 8000; )

  {

  number = number + 1000;

  yield return arr[number];

  }

}

  //Итераторы

  IEnumerator<ITask> IteratorExample(Port<int> resp, InputData1 data)

  {

  Stopwatch sWatch = new Stopwatch();

  sWatch. Start();

  for (int i = 0 ;i < Global. k/Global. nc; i++)

  for (int j = 0; j < Global. k / Global. nc - i - 1; j++)

  if (data. B[j] > data. B[j + 1])

  {

  int tmp;

  tmp = data. B[j];

  data. B[j] = data. B[j + 1];

  data. B[j + 1] = tmp;

  }

  sWatch. Stop();

  Console. WriteLine("P1 Thread {0}: {1}мс", Thread. CurrentThread. ManagedThreadId, sWatch. ElapsedMilliseconds. ToString());

  resp. Post(1);

  yield break;

  }

  void Mul(InputData data, Port<int> resp)

  {  Stopwatch sWatch = new Stopwatch();

  sWatch. Start();

  for (int i = 0; i < Global. k / Global. nc; i++)

  for (int j = 0; j < Global. k / Global. nc - i - 1; j++)

  if (data. B[j] > data. B[j + 1])

  {

  int tmp;

  tmp = data. B[j];

  data. B[j] = data. B[j + 1];

  data. B[j + 1] = tmp;

  }

  sWatch. Stop();

  Console. WriteLine("№ {0}: Параллельный алгоритм = {1} мс.",

  Thread. CurrentThread. ManagedThreadId, sWatch. ElapsedMilliseconds. ToString());

  resp. Post(1);

  }

  }

  class Global

  {

  public static int[] A;

  public static int m;

  public static int s;

  public static int k;

  public static int nc;

  }

}

Результат работы программы

Вывод

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

Как показал ряд опытов, распараллеливание на 2 потока позволяет решать поставленную задачу в 1,5 – 2 раза быстрее (эффективность можно увидеть в тестовом примере), чем при последовательной обработке данных. Также было реализовано распараллеливание с помощью итераторов

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