Параллельное программирование - C#

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

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

Решил накидать простенькую задачу: выполнить какие-нибудь операции над большим блоком данных. И это все распараллелить. Это можно сделать 2мя способами: 1. Параллелить вызов коротеньких процедур. Но тогда будет очень много времени тратиться на то, чтобы передать управление другому ядру. Ведь так? ну нет смысла параллелить операцию 2+2. 2. Параллелить обработку блоков данных. Логично предположить. что когда параллельно запускаться будут тяжелые процедуруы, эффект от параллельности будет гораздо выше. Однако оказались весьма странные результаты. Почему-то первоначальный эффект от параллельности отрицательный. Вот код простой программки, которая наглядно всё демонстрирует:
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;
        }
    }
}
А вот результат. 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 Как видно, во втором случае результат очень плохой. То есть распараллеливание медленно отрабатывает. Почему так? Ведь по логике второй способ распараллеливания должен быть лучше первого?

Решение задачи: «Параллельное программирование»

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++;
            }
        }

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


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

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

6   голосов , оценка 4 из 5
Похожие ответы