Параллельное программирование - 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++; } }
ИИ поможет Вам:
- решить любую задачу по программированию
- объяснить код
- расставить комментарии в коде
- и т.д