Параллельное программирование - C#
Формулировка задачи:
Решил накидать простенькую задачу: выполнить какие-нибудь операции над большим блоком данных. И это все распараллелить. Это можно сделать 2мя способами:
1. Параллелить вызов коротеньких процедур. Но тогда будет очень много времени тратиться на то, чтобы передать управление другому ядру. Ведь так? ну нет смысла параллелить операцию 2+2.
2. Параллелить обработку блоков данных. Логично предположить. что когда параллельно запускаться будут тяжелые процедуруы, эффект от параллельности будет гораздо выше.
Однако оказались весьма странные результаты. Почему-то первоначальный эффект от параллельности отрицательный.
Вот код простой программки, которая наглядно всё демонстрирует:
А вот результат.
1 итерация:
1 поток, время: 2,5947303
2 поток, время: 1,5046816
3 поток, время: 1,2435103
4 поток, время: 1,1743574
5 поток, время: 1,8177255
6 поток, время: 1,8564871
7 поток, время: 1,7038264
8 поток, время: 1,7404472
Блок итераций:
1 поток, время: 1,2824387
2 поток, время: 1,2592897
3 поток, время: 1,3303499
4 поток, время: 1,3710368
5 поток, время: 1,4195757
6 поток, время: 1,4460356
7 поток, время: 1,5213963
8 поток, время: 1,6072681
Как видно, во втором случае результат очень плохой. То есть распараллеливание медленно отрабатывает. Почему так? Ведь по логике второй способ распараллеливания должен быть лучше первого?
Листинг программы
- using System;
- using System.Collections.Generic;
- using System.ComponentModel;
- using System.Data;
- using System.Drawing;
- using System.Linq;
- using System.Text;
- using System.Threading.Tasks;
- using System.Windows.Forms;
- using System.Diagnostics;
- using System.Threading;
- namespace WindowsFormsApplication2
- {
- public partial class Form1 : Form
- {
- public Form1()
- {
- InitializeComponent();
- }
- double [] _dArray = new double[10000000];
- double[] _dArray2 = new double[10000000];
- int _iThreads = 8;
- int _iSizeBlock;
- private void button1_Click(object sender, EventArgs e)
- {
- _iSizeBlock = _dArray.Length / _iThreads;//размер блока
- //заполним массив случайно
- Random r = new Random();
- for (int i = 0; i < _dArray.Length; i++)
- {
- _dArray[i] = r.NextDouble();
- _dArray2[i] = _dArray[i];
- }
- richTextBox1.Text = "1 итерация:\r\n";
- for (int i = 1; i <= 8; i++)
- {
- ParallelOptions options = new ParallelOptions
- {
- MaxDegreeOfParallelism = i
- };
- Stopwatch st1 = new Stopwatch();
- st1.Start();
- Parallel.For(0, _dArray.Length, options, parallelOne);
- st1.Stop();
- richTextBox1.Text += i.ToString() + " поток, время: " + st1.Elapsed.TotalSeconds.ToString() + "\r\n";
- }
- richTextBox1.Text += "Блок итераций:\r\n";
- for (int i = 1; i <= 8; i++)
- {
- ParallelOptions options = new ParallelOptions
- {
- MaxDegreeOfParallelism = i
- };
- Stopwatch st1 = new Stopwatch();
- st1.Start();
- Parallel.For(0, i, options, ParallelBlock);
- st1.Stop();
- richTextBox1.Text += i.ToString() + " поток, время: " + st1.Elapsed.TotalSeconds.ToString() + "\r\n";
- }
- }
- private void ParallelBlock(int iIndex)
- {
- int iStart = iIndex * _iSizeBlock;
- int iEnd = iStart + _iSizeBlock;
- //iIndex - номер блока
- for (int i = iStart; i < iEnd; i++)
- {
- _dArray[i] = Someoperations(_dArray[i]);
- }
- }
- private void parallelOne(int iIndex)
- {
- _dArray[iIndex] = Someoperations(_dArray[iIndex]);
- }
- private double Someoperations(double dInput)
- {
- double Result = Math.Sin(dInput) * Math.Log(dInput + 10);
- Result = Math.Pow(Result, 10);
- Result += Math.Abs(Math.Cos(Result));
- Result += Math.Sqrt(Result);
- Result = Math.Pow(Result, 2);
- return Result;
- }
- }
- }
Решение задачи: «Параллельное программирование»
textual
Листинг программы
- public OneObject(Image<Lab, byte> imgSource,//исходное изображение
- Image<Bgr, byte> imgBinarized,//бинаризованное изображение
- Rectangle rect//область объекта
- )
- {
- watchSegmentation = new Stopwatch();
- int iStopY = rect.Y + rect.Height;
- int iStopX = rect.X + rect.Width;
- _iObjectpixels = 0;
- //узнать число пикселей объекта (по бинаризованному изображению)
- for (int y = rect.Y; y < iStopY; y++)
- {
- for (int x = rect.X; x < iStopX; x++)
- {
- if ((imgBinarized.Data[y, x, 0] < 123) && (imgBinarized.Data[y, x, 1] < 123) && (imgBinarized.Data[y, x, 2] < 123))
- {
- _iObjectpixels++;
- }
- }
- }
- //поместить в матрицу пиксели объекта
- matrSourceObject = new Matrix<float>(_iObjectpixels, 1, 3);
- matrClusteredObject = new Matrix<int>(_iObjectpixels, 1);
- int iObjectpixels = 0;
- //заполнить матрицу изображениями объекта без фона
- for (int y = rect.Y; y < iStopY; y++)
- {
- for (int x = rect.X; x < iStopX; x++)
- {
- if ((imgBinarized.Data[y, x, 0] < 123) && (imgBinarized.Data[y, x, 1] < 123) && (imgBinarized.Data[y, x, 2] < 123))
- {
- matrSourceObject.Data[iObjectpixels, 0] = (float)imgSource[y, x].X;
- matrSourceObject.Data[iObjectpixels, 1] = (float)imgSource[y, x].Y;
- matrSourceObject.Data[iObjectpixels, 2] = (float)imgSource[y, x].Z;
- iObjectpixels++;
- }
- }
- }
- MCvTermCriteria term = new MCvTermCriteria(50, 0.9);
- term.Type = TermCritType.Eps | TermCritType.Iter;
- clusterCount = 2;
- int attempts = 5;
- Matrix<Single> centers = new Matrix<Single>(clusterCount, imgSource.Rows * imgSource.Cols);
- //сегментация
- //еще нужно будет в цикле определять число кластеров
- //но это потом
- double divLastStep = 0, divThisStep = 0, dLastSterpEntr = 0;
- double dEntropy = 0;
- bool bEntrStop = false;
- bool bSKOStop = false;
- List<double> listDobleEntropy = new List<double>();
- List<double> listDoubleSKOMult = new List<double>();
- watchSegmentation.Restart();
- while (true)
- {
- listMatr.Clear();
- try
- {
- watchSegmentation.Start();
- CvInvoke.Kmeans(matrSourceObject, clusterCount, matrClusteredObject, term, attempts, KMeansInitType.PPCenters, centers);
- watchSegmentation.Stop();
- }
- catch
- {
- clusterCount--;
- listMatr.Clear();
- CvInvoke.Kmeans(matrSourceObject, clusterCount, matrClusteredObject, term, attempts, KMeansInitType.PPCenters, centers);
- //поместить все точки объекта в текущею ячейку, в которой будет список из сегментов, в каждом из которых содержатся точки
- MyClass.pointsIntoListClusters(matrSourceObject, matrClusteredObject, listMatr, clusterCount);
- break;
- }
- //поместить все точки объекта в текущею ячейку, в которой будет список из сегментов, в каждом из которых содержатся точки
- MyClass.pointsIntoListClusters(matrSourceObject, matrClusteredObject, listMatr, clusterCount);
- //определяем максимальную энтропию по всем кластерам
- listDobleEntropy.Clear();
- listDoubleSKOMult.Clear();
- //watchSegmentation.Start();
- listDobleEntropy = MyMath.GetEntropyInAllClusters(listMatr);
- //watchSegmentation.Start();
- dEntropy = MyMath.Max(listDobleEntropy);
- //проверка критерия останова по энтропии
- if (dEntropy < dLastSterpEntr)
- {
- bEntrStop = true;
- }
- //определяем произведение СКО компонент для каждого кластера
- double[] dSKOMult = new double[clusterCount];
- for (int i = 0; i < clusterCount; i++)
- {
- dSKOMult[i] = 1;
- dSKOMult[i] *= MyMath.GetMeanSquareDiviation(listMatr[i], 0);
- dSKOMult[i] *= MyMath.GetMeanSquareDiviation(listMatr[i], 1);
- dSKOMult[i] *= MyMath.GetMeanSquareDiviation(listMatr[i], 2);
- }
- divThisStep = MyMath.Max(dSKOMult) / MyMath.Min(dSKOMult);
- if (divThisStep < divLastStep)
- {
- bSKOStop = true;
- }
- //условие выхода из цикла
- if ((bSKOStop && bEntrStop) || (clusterCount >= 9))
- {
- clusterCount++;
- watchSegmentation.Start();
- try
- {
- listMatr.Clear();
- CvInvoke.Kmeans(matrSourceObject, clusterCount, matrClusteredObject, term, attempts, KMeansInitType.PPCenters, centers);
- }
- catch
- {
- listMatr.Clear();
- clusterCount--;
- CvInvoke.Kmeans(matrSourceObject, clusterCount, matrClusteredObject, term, attempts, KMeansInitType.PPCenters, centers);
- //поместить все точки объекта в текущею ячейку, в которой будет список из сегментов, в каждом из которых содержатся точки
- }
- finally
- {
- MyClass.pointsIntoListClusters(matrSourceObject, matrClusteredObject, listMatr, clusterCount);
- }
- watchSegmentation.Stop();
- break;
- }
- divLastStep = divThisStep;
- dLastSterpEntr = MyMath.Max(listDobleEntropy);
- clusterCount++;
- }
- iSegmentsInObject = clusterCount;
- //вывод результата в красивой картинке
- imgSegmentedObject = new Image<Bgr, byte>(new System.Drawing.Size(rect.Width, rect.Height));
- imgObject = new Image<Lab, byte>(new System.Drawing.Size(rect.Width, rect.Height));
- iObjectpixels = 0;
- int iColorNumber = 0;
- int iy = 0;
- for (int y = rect.Y; y < iStopY; y++)
- {
- int ix = 0;
- for (int x = rect.X; x < iStopX; x++)
- {
- if ((imgBinarized.Data[y, x, 0] < 123) && (imgBinarized.Data[y, x, 1] < 123) && (imgBinarized.Data[y, x, 2] < 123))
- {
- iColorNumber = matrClusteredObject.Data[iObjectpixels, 0];
- imgSegmentedObject.Data[iy, ix, 0] = (byte)clusterColors[iColorNumber].Red;
- imgSegmentedObject.Data[iy, ix, 1] = (byte)clusterColors[iColorNumber].Green;
- imgSegmentedObject.Data[iy, ix, 2] = (byte)clusterColors[iColorNumber].Blue;
- imgObject.Data[iy, ix, 0] = (byte)matrSourceObject.Data[iObjectpixels, 0];
- imgObject.Data[iy, ix, 1] = (byte)matrSourceObject.Data[iObjectpixels, 1];
- imgObject.Data[iy, ix, 2] = (byte)matrSourceObject.Data[iObjectpixels, 2];
- iObjectpixels++;
- }
- else
- {
- imgSegmentedObject.Data[iy, ix, 0] = 255;
- imgSegmentedObject.Data[iy, ix, 1] = 255;
- imgSegmentedObject.Data[iy, ix, 2] = 255;
- imgObject.Data[iy, ix, 0] = 255;
- imgObject.Data[iy, ix, 1] = 125;
- imgObject.Data[iy, ix, 2] = 125;
- }
- ix++;
- }
- iy++;
- }
- }
ИИ поможет Вам:
- решить любую задачу по программированию
- объяснить код
- расставить комментарии в коде
- и т.д