Параллельное программирование для ускорения обработки информации - C#

Узнай цену своей работы

Формулировка задачи:

Мне необходимо выполнить бинаризацию изображения с использованием k-means на 2 кластера. Делаю я следующим образом: 1. сначала я подготавливаю массив массивов. Чтобы каждая ячейка соответствовала своему потоку. и в каждой ячейке содержались только те данные, которые будет своё ядро обрабатывать. Для оптимизации так сделал. вот таким образом я раскидываю. Тут вроде ничего интересного. Всё правильно вроде. Просто так код приложил
Листинг программы
  1. public void IdentifyPointsArray(int iSize, int iThreadCount)
  2. {
  3. iPointPointer = 0; // указатель на текущую точку
  4. _iPointsInEveryThread = iSize / iThreadCount;
  5. _iDivThread = iSize % iThreadCount;
  6. _dPointsArrayParallel = new double[iThreadCount][][];//сюда нужно раскидать точки изображения _dPoints[][]
  7. for (int i = 0; i < iThreadCount; i++)
  8. {
  9. if (iThreadCount - i > 1)
  10. {
  11. _dPointsArrayParallel[i] = new double[_iPointsInEveryThread][];
  12. }
  13. else
  14. {
  15. _dPointsArrayParallel[i] = new double[_iPointsInEveryThread + _iDivThread][];
  16. }
  17.  
  18. int iPointsInThread = _dPointsArrayParallel[i].Length;
  19. for (int j = 0; j < iPointsInThread; j++)
  20. {
  21. _dPointsArrayParallel[i][j] = new double[3];
  22. //раскидать точки по ячейкам массива точек для потоков
  23. _dPointsArrayParallel[i][j][0] = _dPoints[iPointPointer][0];
  24. _dPointsArrayParallel[i][j][1] = _dPoints[iPointPointer][1];
  25. _dPointsArrayParallel[i][j][2] = _dPoints[iPointPointer][2];
  26. iPointPointer++;
  27. }
  28. }
  29. }
Затем я выполняю бинаризацию изображения (все точки изображения делю на 2 класса). Приложил код. Вдруг я меряю время неправильно. Мне нужно замерять время выполнения GetBarycentresParallel
Листинг программы
  1. Stopwatch stMy = new Stopwatch();
  2. stMy.Reset();
  3. stMy.Start();
  4. kMeansObject.GetBarycentresParallel(j);
  5. stMy.Stop();
  6. dTime[i] = stMy.Elapsed.TotalSeconds;
  7. dSumTime += dTime[i];
Всю функцию GetBarycentresParallel не стал приводить, приведу наиболее значимый её кусок (во этого объявления переменных и прочая ерунда, не сильно нагружающая процессор
Листинг программы
  1. while (true)
  2. {
  3. iCountSteps++;
  4. //занулить суммы
  5. _dPointsSum[0, 0] = 0;
  6. _dPointsSum[0, 1] = 0;
  7. _dPointsSum[0, 2] = 0;
  8. _dPointsSum[1, 0] = 0;
  9. _dPointsSum[1, 1] = 0;
  10. _dPointsSum[1, 2] = 0;
  11. _iPointsIn0 = 0;
  12. _iPointsIn1 = 0;
  13. ////////////////////////////////////////////////////////////////////
  14. //1. определить кластеры по текущим центрам
  15. Parallel.For(0, iThreadsCount, options, IdentifyPointIntoClusterByThreadArray);
  16. dPointsInclust[0] = _iPointsIn0;
  17. dPointsInclust[1] = _iPointsIn1;
  18. //2. Определить новые центры кластеров
  19. //сохранить значения центров кластеров на предыдущем шаге
  20. _dBaryCentresPrevious[0][0] = _dBaryCentres[0][0];
  21. _dBaryCentresPrevious[0][1] = _dBaryCentres[0][1];
  22. _dBaryCentresPrevious[0][2] = _dBaryCentres[0][2];
  23. _dBaryCentresPrevious[1][0] = _dBaryCentres[1][0];
  24. _dBaryCentresPrevious[1][1] = _dBaryCentres[1][1];
  25. _dBaryCentresPrevious[1][1] = _dBaryCentres[1][2];
  26. for (int i = 0; i < 2; i++)
  27. {
  28. for (int j = 0; j < 3; j++)
  29. {
  30. //сохраняем значение
  31. _dBaryCentresPrevious[i][j] = _dBaryCentres[i][j];
  32. _dBaryCentres[i][j] = _dPointsSum[i, j] / dPointsInclust[i];
  33. }
  34. }
  35. dTotalSum = EvclidDistance(_dBaryCentres[0], _dBaryCentresPrevious[0]);
  36. dTotalSum += EvclidDistance(_dBaryCentres[1], _dBaryCentresPrevious[1]);
  37. if (iCountSteps > 10)
  38. {
  39. break;
  40. }
  41. }
Самое интересное - эта строчка. От неё все и зависит. Вот код функции
Листинг программы
  1. public void IdentifyPointsArray(int iSize, int iThreadCount)
  2. {
  3. iPointPointer = 0; // указатель на текущую точку
  4. _iPointsInEveryThread = iSize / iThreadCount;
  5. _iDivThread = iSize % iThreadCount;
  6. _dPointsArrayParallel = new double[iThreadCount][][];//сюда нужно раскидать точки изображения _dPointe[][]
  7. for (int i = 0; i < iThreadCount; i++)
  8. {
  9. if (iThreadCount - i > 1)
  10. {
  11. _dPointsArrayParallel[i] = new double[_iPointsInEveryThread][];
  12. }
  13. else
  14. {
  15. _dPointsArrayParallel[i] = new double[_iPointsInEveryThread + _iDivThread][];
  16. }
  17.  
  18. int iPointsInThread = _dPointsArrayParallel[i].Length;
  19. for (int j = 0; j < iPointsInThread; j++)
  20. {
  21. _dPointsArrayParallel[i][j] = new double[3];
  22. //раскидать точки по ячейкам массива точек для потоков
  23. _dPointsArrayParallel[i][j][0] = _dPoints[iPointPointer][0];
  24. _dPointsArrayParallel[i][j][1] = _dPoints[iPointPointer][1];
  25. _dPointsArrayParallel[i][j][2] = _dPoints[iPointPointer][2];
  26. iPointPointer++;
  27. }
  28. }
  29. }
Вроде бы самое сложное место распараллелил. Логично, что если 1 ядря, то выполняется, например, 100 секунд, если 2 ядра то 50 секунд, если 3 то 30 и так далее. Естественно, 50 и 30 это идеальные варианты и вполне неплохо было бы, если бы было 60 и 40, как пример. Но у меня совсем не то что надо получается. вот мои результаты. Распараллеливание даже отрицательный эффект по скорости дало почему-то: Size image {Width=3976, Height=3299} time 34,45929 processors 1 Size image {Width=3976, Height=3299} time 52,25169305 processors 2 Size image {Width=3976, Height=3299} time 49,773416025 processors 3 Size image {Width=3976, Height=3299} time 44,0997120125 processors 4 Size image {Width=3976, Height=3299} time 38,79137545625 processors 5 Size image {Width=3976, Height=3299} time 34,887025578125 processors 6 Size image {Width=3976, Height=3299} time 31,8754485390625 processors 7 Size image {Width=3976, Height=3299} time 29,6087524195313 processors 8 Size image {Width=3976, Height=3299} time 27,7327576597656 processors 9 Size image {Width=3976, Height=3299} time 26,4133148798828 processors 10 Size image {Width=3976, Height=3299} time 25,2272720399414 processors 11 Size image {Width=3976, Height=3299} time 24,6323545199707 processors 12 Процессор i7-3930k. Количество ядер процессора 6, количество потоков процессора 12. Почему так печально у меня получается со скоростью?
У кого-нибудь есть идеи, почему так может быть?

Решение задачи: «Параллельное программирование для ускорения обработки информации»

textual
Листинг программы
  1.   class Program
  2.     {
  3.         static void Main()
  4.         {
  5.             double[] array = new double[20  * 1000 * 1000];
  6.  
  7.             for (int i = 0; i < array.Length; i++)
  8.                 array[i] = 1;
  9.  
  10.             for (int i = 0; i < 5; i++)
  11.             {
  12.                 Stopwatch sw = Stopwatch.StartNew();
  13.                 Serial(array, 2);
  14.                 Console.WriteLine("Serial: {0:f2} s", sw.Elapsed.TotalSeconds);
  15.  
  16.                 sw = Stopwatch.StartNew();
  17.                 ParallelFor(array, 2);
  18.                 Console.WriteLine("Parallel.For: {0:f2} s", sw.Elapsed.TotalSeconds);
  19.  
  20.                 sw = Stopwatch.StartNew();
  21.                 ParallelForDegreeOfParallelism(array, 2);
  22.                 Console.WriteLine("Parallel.For (degree of parallelism): {0:f2} s", sw.Elapsed.TotalSeconds);
  23.  
  24.                 sw = Stopwatch.StartNew();
  25.                 CustomParallel(array, 2);
  26.                 Console.WriteLine("Custom parallel: {0:f2} s", sw.Elapsed.TotalSeconds);
  27.  
  28.                 sw = Stopwatch.StartNew();
  29.                 CustomParallelExtractedMax(array, 2);
  30.                 Console.WriteLine("Custom parallel (extracted max): {0:f2} s", sw.Elapsed.TotalSeconds);
  31.  
  32.                 sw = Stopwatch.StartNew();
  33.                 CustomParallelExtractedMaxHalfParallelism(array, 2);
  34.                 Console.WriteLine("Custom parallel (extracted max, half parallelism): {0:f2} s", sw.Elapsed.TotalSeconds);
  35.  
  36.                 sw = Stopwatch.StartNew();
  37.                 CustomParallelFalseSharing(array, 2);
  38.                 Console.WriteLine("Custom parallel (false sharing): {0:f2} s", sw.Elapsed.TotalSeconds);
  39.                 Console.ReadKey();
  40.             }
  41.         }
  42.  
  43.         static void Serial(double[] array, double factor)
  44.         {
  45.             for (int i = 0; i < array.Length; i++)
  46.             {
  47.                 array[i] = array[i] * factor;
  48.             }
  49.         }
  50.  
  51.         static void ParallelFor(double[] array, double factor)
  52.         {
  53.             Parallel.For(
  54.                 0, array.Length, i => { array[i] = array[i] * factor; });
  55.         }
  56.  
  57.         static void ParallelForDegreeOfParallelism(double[] array, double factor)
  58.         {
  59.             Parallel.For(
  60.                 0, array.Length, new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount },
  61.                 i => { array[i] = array[i] * factor; });
  62.         }
  63.  
  64.         static void CustomParallel(double[] array, double factor)
  65.         {
  66.             var degreeOfParallelism = Environment.ProcessorCount;
  67.  
  68.             var tasks = new Task[degreeOfParallelism];
  69.  
  70.             for (int taskNumber = 0; taskNumber < degreeOfParallelism; taskNumber++)
  71.             {
  72.                 // capturing taskNumber in lambda wouldn't work correctly
  73.                 int taskNumberCopy = taskNumber;
  74.  
  75.                 tasks[taskNumber] = Task.Factory.StartNew(
  76.                     () =>
  77.                     {
  78.                         for (int i = array.Length * taskNumberCopy / degreeOfParallelism;
  79.                             i < array.Length * (taskNumberCopy + 1) / degreeOfParallelism;
  80.                             i++)
  81.                         {
  82.                             array[i] = array[i] * factor;
  83.                         }
  84.                     });
  85.             }
  86.  
  87.             Task.WaitAll(tasks);
  88.         }
  89.  
  90.         static void CustomParallelExtractedMax(double[] array, double factor)
  91.         {
  92.             var degreeOfParallelism = Environment.ProcessorCount;
  93.  
  94.             var tasks = new Task[degreeOfParallelism];
  95.  
  96.             for (int taskNumber = 0; taskNumber < degreeOfParallelism; taskNumber++)
  97.             {
  98.                 // capturing taskNumber in lambda wouldn't work correctly
  99.                 int taskNumberCopy = taskNumber;
  100.  
  101.                 tasks[taskNumber] = Task.Factory.StartNew(
  102.                     () =>
  103.                     {
  104.                         var max = array.Length * (taskNumberCopy + 1) / degreeOfParallelism;
  105.                         for (int i = array.Length * taskNumberCopy / degreeOfParallelism;
  106.                             i < max;
  107.                             i++)
  108.                         {
  109.                             array[i] = array[i] * factor;
  110.                         }
  111.                     });
  112.             }
  113.  
  114.             Task.WaitAll(tasks);
  115.         }
  116.  
  117.         static void CustomParallelExtractedMaxHalfParallelism(double[] array, double factor)
  118.         {
  119.             var degreeOfParallelism = Environment.ProcessorCount / 2;
  120.  
  121.             var tasks = new Task[degreeOfParallelism];
  122.  
  123.             for (int taskNumber = 0; taskNumber < degreeOfParallelism; taskNumber++)
  124.             {
  125.                 // capturing taskNumber in lambda wouldn't work correctly
  126.                 int taskNumberCopy = taskNumber;
  127.  
  128.                 tasks[taskNumber] = Task.Factory.StartNew(
  129.                     () =>
  130.                     {
  131.                         var max = array.Length * (taskNumberCopy + 1) / degreeOfParallelism;
  132.                         for (int i = array.Length * taskNumberCopy / degreeOfParallelism;
  133.                             i < max;
  134.                             i++)
  135.                         {
  136.                             array[i] = array[i] * factor;
  137.                         }
  138.                     });
  139.             }
  140.  
  141.             Task.WaitAll(tasks);
  142.         }
  143.  
  144.          static void CustomParallelFalseSharing(double[] array, double factor)
  145.         {
  146.             var degreeOfParallelism = Environment.ProcessorCount;
  147.  
  148.             var tasks = new Task[degreeOfParallelism];
  149.  
  150.             int i = -1;
  151.  
  152.             for (int taskNumber = 0; taskNumber < degreeOfParallelism; taskNumber++)
  153.             {
  154.                 tasks[taskNumber] = Task.Factory.StartNew(
  155.                     () =>
  156.                     {
  157.                         int j = Interlocked.Increment(ref i);
  158.                         while (j < array.Length)
  159.                         {
  160.                             array[j] = array[j] * factor;
  161.                             j = Interlocked.Increment(ref i);
  162.                         }
  163.                     });
  164.             }
  165.  
  166.             Task.WaitAll(tasks);
  167.         }
  168.     }

ИИ поможет Вам:


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

Оцени полезность:

5   голосов , оценка 4.2 из 5

Нужна аналогичная работа?

Оформи быстрый заказ и узнай стоимость

Бесплатно
Оформите заказ и авторы начнут откликаться уже через 10 минут
Похожие ответы