Форум программистов, компьютерный форум, киберфорум
C# для начинающих
Войти
Регистрация
Восстановить пароль
Карта форума Темы раздела Блоги Сообщество Поиск Заказать работу  
 
 
Рейтинг 4.68/25: Рейтинг темы: голосов - 25, средняя оценка - 4.68
0 / 0 / 1
Регистрация: 27.12.2014
Сообщений: 298
1

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

08.10.2016, 01:26. Показов 4764. Ответов 23
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Решил накидать простенькую задачу: выполнить какие-нибудь операции над большим блоком данных. И это все распараллелить. Это можно сделать 2мя способами:
1. Параллелить вызов коротеньких процедур. Но тогда будет очень много времени тратиться на то, чтобы передать управление другому ядру. Ведь так? ну нет смысла параллелить операцию 2+2.
2. Параллелить обработку блоков данных. Логично предположить. что когда параллельно запускаться будут тяжелые процедуруы, эффект от параллельности будет гораздо выше.
Однако оказались весьма странные результаты. Почему-то первоначальный эффект от параллельности отрицательный.
Вот код простой программки, которая наглядно всё демонстрирует:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
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

Как видно, во втором случае результат очень плохой. То есть распараллеливание медленно отрабатывает. Почему так? Ведь по логике второй способ распараллеливания должен быть лучше первого?
0
Лучшие ответы (1)
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
08.10.2016, 01:26
Ответы с готовыми решениями:

Параллельное программирование
Всем привет. Начал изучать параллельное программирование в .NET. Столкнулся с рядом проблем и...

Нужны задачи на параллельное программирование
Курсовая по пар. программированию.. Не могу придумать задачи, точнее не знаю что это должно быть

Служба Windows и параллельное программирование
Здравствуйте Форумчане, пишу свою службу Windows и приложение к нему. Будет эта связка бэкапить...

Параллельное программирование и библиотека TPL
Здравствуйте! Это моя третья тема за этот месяц на Cyberforum, также я создавал те же темы и на...

23
Эксперт .NET
5534 / 4298 / 1217
Регистрация: 12.10.2013
Сообщений: 12,332
Записей в блоге: 2
08.10.2016, 09:48 2
Dimarik__1, на RSDN была неплохая статья на эту тему (немного вольный перевод глав из книги Албахари), но сейчас ее уже нет, как видно удалили. У меня есть копия в pdf, вот прикрепляю, почитайте. Довольно интересный материал.
Вложения
Тип файла: pdf C#_Part_3.pdf (966.5 Кб, 67 просмотров)
3
0 / 0 / 1
Регистрация: 27.12.2014
Сообщений: 298
09.10.2016, 22:44  [ТС] 3
Спасибо. Прочитал. Ну получается, для данного примера следует использовать либо Parallel.For либо PINQ. Однако Parallel.Fro более оптимизирован. Написано что лучше не использовать внутреннее распараллеливание так как оно медленнее отрабатывает чем внешнее. Я так и сделал. Тем не менее странные результаты, которые не объясняются никак. А моя задача максимально эффективно распараллелить.

Добавлено через 22 часа 54 минуты
Вы можете подсказать, как можно написанный мной код переписать с использованием PLINQ?

Добавлено через 7 часов 10 минут
Я нашел вот такое в Интернете.
C#
1
2
3
4
5
6
7
8
9
10
11
 Thread.BeginThreadAffinity();
                        foreach(ProcessThread pt in Process.GetCurrentProcess().Threads)
            {
                int utid = GetCurrentThreadId();
                if (utid == pt.Id)
                {
                    pt.ProcessorAffinity = (IntPtr)(_iCPUThread); // Set affinity for this
                    AllIterations();
                }
            }
            Thread.EndThreadAffinity();
Может быть таким способом можно как-то более оптимально решить мою проблему и код получится ускорить? Можете подсказать? А то совсем как-то тупик. Можно ли код, который я написал выше, распараллелить с использованием приведенного выше мной примера? Основная сложность заключается в передаче индекса в поток. Ведь массив по индексу ведь обрабатываю
Спасибо

Добавлено через 1 час 45 минут
Можете пояснить, почему цикл for выполняется быстрее чем parallel.For?
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
double[] _dArray = new double[20];
        double[] _dArray2 = new double[20];
        int _iThreads = 12;
        int _iSizeBlock;
 
        private void button2_Click(object sender, EventArgs e)
        {
            ParallelOptions options = new ParallelOptions
            {
                MaxDegreeOfParallelism = Environment.ProcessorCount
            };
            Random r = new Random();
            for (int i = 0; i < _dArray.Length; i++)
            {
                _dArray[i] = r.NextDouble();
                _dArray2[i] = _dArray[i];
            }
 
 
 
            Stopwatch st2 = new Stopwatch();
            st2.Start();
            for (int i = 0; i < _dArray.Length; i++)
            {
                _dArray[i] = GetEntropyDoubleArray();
            }
            st2.Stop();
 
            GC.Collect();
 
            Stopwatch st1 = new Stopwatch();
            st1.Start();
            Parallel.For(0, _dArray.Length, options, parallelOneSomething);
            st1.Stop();
 
            richTextBox1.Text = "Time withought parallel = " + Convert.ToString(st1.Elapsed.TotalSeconds) + "\r\n";
            richTextBox1.Text += "Time with parallel = " + Convert.ToString(st2.Elapsed.TotalSeconds) + "\r\n";
        }
        private void parallelOneSomething(int iIndsx)
        {
            _dArray[iIndsx] = GetEntropyDoubleArray() ;
        }
 
        private double GetEntropyDoubleArray()
        {
            double dResult = 0;
            //get Random array
            double [] dArrayRandom = new double[1000];
            Random rNew = new Random();
            for (int i = 0; i < dArrayRandom.Length; i++)
            {
                dArrayRandom[i] = rNew.Next(0, 100);
 
            }
            double [] dProbabilities = new double[dArrayRandom.Length];
            int iTemp;
            // get entropy
            for (int i = 0; i < dArrayRandom.Length; i++)
            {
                iTemp = (int)dArrayRandom[i];
                dProbabilities[iTemp]++;
            }
 
            for (int j = 0; j < 10000; j++)//cycle to be harder
            {
                for (int i = 0; i < dArrayRandom.Length; i++)
                {
                    dProbabilities[i] /= dArrayRandom.Length;
                    dResult += dProbabilities[i] * Math.Log10(dProbabilities[i]);
                }
            }
 
            return dResult;
        }
Time withought parallel = 6,8884986
Time with parallel = 56,7273746
0
1150 / 742 / 483
Регистрация: 21.01.2014
Сообщений: 1,903
09.10.2016, 23:33 4
Цитата Сообщение от Dimarik__1 Посмотреть сообщение
Можете пояснить, почему цикл for выполняется быстрее чем parallel.For?
Потому что вы перепутали таймеры, при выводе времени выполнения.
0
Неадекват
1492 / 1230 / 246
Регистрация: 02.04.2010
Сообщений: 2,789
09.10.2016, 23:34 5
Цитата Сообщение от Dimarik__1 Посмотреть сообщение
Можете пояснить, почему цикл for выполняется быстрее чем parallel.For?
Потому что st1 замеряет параллельную версию, но в результатах пишется как последовательная...
1
0 / 0 / 1
Регистрация: 27.12.2014
Сообщений: 298
10.10.2016, 00:03  [ТС] 6
да. Вы правы. Както проглядел. А по поводу основного сообщения темы, вы можете дать ответ? Спасибо.
Я эту проверку с циклом for делал чтобы получше понять Perallel.For.
В основной программе у меня следующая проблема возникла.
Вот участок кода
C#
1
2
3
4
5
6
7
8
9
            //получить пиксели только объектов
            ParallelOptions options = new ParallelOptions
            {
                MaxDegreeOfParallelism = iThreads
            };
            watchSegments.Start();
            //сегментация
            Parallel.For(0, listObjectsWork[iCountInList].listRect.Count, options, ProcessObjectList);
            watchSegments.Stop();
Наилучшие результаты по скорости у меня при iThreads==1. А когда потоков больше одного, тогда падает скорость очень сильно.
Вот эта функция
C#
1
2
3
4
5
private void ProcessObjectList(int index)
        {
            GC.Collect();
            listObjectsWork[iCountInList].allObjects.Add(new OneObject(src, listObjectsWork[iCountInList].imgBinarized, listObjectsWork[iCountInList].listRect[index]));
        }
Почему может так медленно работать при распараллеливании?

Добавлено через 6 минут
как один из вариантов, из-за GC.Collect()
Убрал я его. В результате время при числе потоков следующее
1: 4 сек
2: 11 сек
3: 22 сек
4: 44 сек
0
Неадекват
1492 / 1230 / 246
Регистрация: 02.04.2010
Сообщений: 2,789
10.10.2016, 00:29 7
Dimarik__1, не понятно, что вы хотите распараллелить. Опишите задачу.
0
0 / 0 / 1
Регистрация: 27.12.2014
Сообщений: 298
10.10.2016, 09:54  [ТС] 8
У меня есть картинка, на которой на белом фоне сфотографированы яблоки. Мне нужно выделить каждое яблочко в отдельную картинку и сегментировать каждое яблочко.
Я делаю это следующим образом:
1. Получаю контуры каждого яблока. Вот здесь они хранятся
2.И затем создаю список объектов listObjectsWork[iCountInList].allObjects, в каждом из которых будет единичных объект яблоко, которое разбито на сегменты. У меня в конструкторе происходит выделение яблоко в отдельный объект из общего изображения. И затем сегментация. Может быть у меня тормоза идут из-за того что я к одному общему объекту постоянно обращаюсь?
Вот код конструктора:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
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++;
            }
        }
0
Неадекват
1492 / 1230 / 246
Регистрация: 02.04.2010
Сообщений: 2,789
10.10.2016, 11:34 9
Dimarik__1, боюсь, без OpenCV на такой задаче вменяемых скоростей вы не получите. Хоть с TPL, хоть без нее.
0
0 / 0 / 1
Регистрация: 27.12.2014
Сообщений: 298
10.10.2016, 11:42  [ТС] 10
Так у меня EMGUCV. EMGUCV это и есть OpenCV но под шарп.
И вопрос именно в распараллеливании. Почему при распараллеливании скорость падает
0
.NET senior
440 / 358 / 137
Регистрация: 23.09.2016
Сообщений: 980
10.10.2016, 11:44 11
Dimarik__1, попробуйте воспользоваться примером из code gallery с сайта emgu.cv:

Кликните здесь для просмотра всего текста

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
            string desktopDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
            string filePath = Path.Combine(desktopDirectory, "Apples.png");
 
            Assert.IsTrue(File.Exists(filePath));
 
            Image<Bgr, byte> sourceImg = new Image<Bgr, byte>(filePath);
            sourceImg = sourceImg.Resize(400, 400, Inter.Linear, true);
 
            UMat uimage = new UMat();
            CvInvoke.CvtColor(sourceImg, uimage, ColorConversion.Bgr2Gray);
 
            UMat pyrdown = new UMat();
            CvInvoke.PyrDown(uimage, pyrdown);
            CvInvoke.PyrUp(pyrdown, uimage);
 
            CircleF[] circles = CvInvoke.HoughCircles(uimage, HoughType.Gradient, 2.0, 20.0, 180.0, 120, 5);
            
            for (int idx = 0; idx < circles.Length; ++idx)
            {
                CircleF current = circles[idx];
 
                Point center = Point.Round(current.Center);
                int radius = (int)current.Radius;
 
                CvInvoke.Circle(sourceImg, center, radius, new Bgr(Color.Black).MCvScalar, 2);
            }
 
            string outfilePath = Path.Combine(desktopDirectory, "Apples_detected.png");
            sourceImg.Save(outfilePath);


В тесте без всякой параллельности детектирование яблок прокручивается за ~1 секунду. Анализируемое и результирующее изображение - во вложениях.
Миниатюры
Параллельное программирование   Параллельное программирование  
0
.NET senior
440 / 358 / 137
Регистрация: 23.09.2016
Сообщений: 980
10.10.2016, 11:47 12
Цитата Сообщение от Dimarik__1 Посмотреть сообщение
Почему при распараллеливании скорость падает
Потому что параллельность только дополнительно даёт нагрузку на исполняющую среду. При работе с обёрткой Emgu.CV могу посоветовать выносить код, исполняющийся долгое время, в фоновый поток (чтобы не вис поток GUI). Этого более чем достаточно.
0
0 / 0 / 1
Регистрация: 27.12.2014
Сообщений: 298
10.10.2016, 12:08  [ТС] 13
У меня сегментация яблок работает очень долго. Именно сегментация яблок, а не их выделение из фона. Вот пример сегментации.
Автоматически я определяю число сегментов, из которых яблоки состоят.
вот таким вот образом я определяю:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
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++;
            }
        }
В результате. Если на фото 16 яблок, то для 1 потока у меня 4 секунды занимает, для 2ух потоков 11, для 3х потоков 22, для 4х потоков 44.
а хотелось бы каждое яблоко обрабатывать отдельно в своем потоке на отдельном ядре
Изображения
  
0
.NET senior
440 / 358 / 137
Регистрация: 23.09.2016
Сообщений: 980
10.10.2016, 12:10 14
Dimarik__1, скиньте изображение, которое анализируете - попробую прокрутить его в своём тесте и скажу, сколько это занимает по времени.
0
0 / 0 / 1
Регистрация: 27.12.2014
Сообщений: 298
10.10.2016, 12:14  [ТС] 15
Вот изображение. Но проблема именно в сегментации. Это самый медленный кусок. Алгоритм сегментации сам разрабатывал для своих задач. Каждое яблоко сегментируется отдельно независимо от другого. Это логично их распараллелить чтобы ускорить выполнение кода. Но в результате все только хуже работает после параллельности. График загрузки процессоров показывает что все загружено (через диспетчер задач), но тем не менее скорости не прибавляется
Миниатюры
Параллельное программирование  
0
.NET senior
440 / 358 / 137
Регистрация: 23.09.2016
Сообщений: 980
10.10.2016, 12:45 16
Dimarik__1, максимум, чего удалось добиться мне - обнаружить 9 яблок из 14. Картинка во вложении.

Код:
Кликните здесь для просмотра всего текста

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
            string desktopDirectory = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
            string filePath = Path.Combine(desktopDirectory, "Apples.jpg");
 
            Image<Bgr, byte> sourceImg = new Image<Bgr, byte>(filePath);
            
            UMat uimage = new UMat();
            CvInvoke.CvtColor(sourceImg, uimage, ColorConversion.Bgr2Gray);
 
            UMat pyrdown = new UMat();
            CvInvoke.PyrDown(uimage, pyrdown);
            CvInvoke.PyrUp(pyrdown, uimage);
 
            CvInvoke.EqualizeHist(uimage, uimage);
 
            uimage.Save(Path.Combine(desktopDirectory, "Apples_uimage.png"));
 
            CircleF[] circles = CvInvoke.HoughCircles(uimage, HoughType.Gradient, 2.0, 20.0, 150.0, 120.0, 5, 300);
            
            for (int idx = 0; idx < circles.Length; ++idx)
            {
                CircleF current = circles[idx];
 
                Point center = Point.Round(current.Center);
                int radius = (int)current.Radius;
 
                CvInvoke.Circle(sourceImg, center, radius, new Bgr(Color.Black).MCvScalar, 2);
            }
 
            string outfilePath = Path.Combine(desktopDirectory, "Apples_detected.png");
            sourceImg.Save(outfilePath);


Тест всё так же успешно отрабатывает примерно за 1 секунду.

Попробуйте в предложенном коде динамически поиграться с параметрами param1 и param2 метода HoughCircles (пороговые значения обнаружения границ на изображении) для достижения максимально высокого качества обнаружения.
Миниатюры
Параллельное программирование  
0
0 / 0 / 1
Регистрация: 27.12.2014
Сообщений: 298
10.10.2016, 15:19  [ТС] 17
я же говорю. у меня не проблема в том чтобы единичные объекты выделить. Мне надо их сегментировать по своему алгоритму для своих задач. Каждый объект отдельно надо разбить на сегменты. Так вот. Эта сегментация работает с каждым объектом по-отдельности. и мне надо распараллелить. а у меня тормоза при распараллеливании сегментации. А не при выделении единичных объектов

Добавлено через 2 часа 28 минут
Решил проверить, каким за сколько времени обрабатывается картинка на разном числе потоков:
1. Получаю картинку и вызываю функцию обработки:
C#
1
2
3
4
5
imagesArray[i] = new Image<Lab, byte>(ofd.FileNames[i]);
                src = imagesArray[i];
          
                //strTimeParametres.Add(getTotalTime(imagesArray[i], i.ToString()));
                getTotalTimeAllThreads(i.ToString());
Вот код этой функции. Циклом по числу потоков я пробую обработать изображение и узнать, за какое время у меня эта обработка выполнилась при разном числе потоков
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
private void getTotalTimeAllThreads(string strOnlyfileName)
        {
         
            int iThreadsMax = (int)numericUpDown1.Value;//максимальное число потоков
            strParapetresTimeAllSystem bigData = new strParapetresTimeAllSystem();
             List<strParapetresTime> allSystemReal = new List<strParapetresTime>();
                List<strParapetresTime> allSystemAmdals = new List<strParapetresTime>();
                List<strParapetresTime> allSystemSegmentation = new List<strParapetresTime>();
                List<strParapetresTime> allSystemPirson = new List<strParapetresTime>();
           for (int i = 1; i <= iThreadsMax; i++)
            {
                GC.Collect();
                if (i == 0)
                {
                   bigData = getTotalTimeOneThread(src, strOnlyfileName, i, 0);
                }
                else
                {
                    bigData = getTotalTimeOneThread(src, strOnlyfileName, i, bigData.dAlpha);
                }
                allSystemReal.Add(bigData.allSystemRealTime);
                allSystemAmdals.Add(bigData.allSystemAmdals);
                allSystemSegmentation.Add(bigData.allSegmentation);
                allSystemPirson.Add(bigData.allPirson);
 
 
            }
 
 
 
            _strTimeParametresAllSystemRealTime.Add(allSystemReal);
            _strTimeParametresAllSystemAmdals.Add(allSystemAmdals);
            _strTimeParametresSegmentation.Add(allSystemSegmentation);
            _strTimeParametresPirson.Add(allSystemPirson);
 
        }
Вот описание функции, которую я в цикле вызываю:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
private strParapetresTimeAllSystem getTotalTimeOneThread(Image<Lab, byte> thisImage, string strOnlyfileName, int iThreads, double dAlphaParam = 0)
        {
            //большая структура для возврата
            strParapetresTimeAllSystem BigStruct = new strParapetresTimeAllSystem();
 
            strParapetresTime strForReturnTemp = new strParapetresTime();
 
            double dTimeBinarization = 0;
            double dTimeSegmentation = 0;
            double dTimeAdditional = 0;
            double dTimeGetPirsonForParallel = 0;
            double dAlpha = 0;//для хакона Амдала
 
            watchAdditionalTime.Reset();
 
            //src = new Image<Lab, byte>(strFileName);
            watchAdditionalTime.Start();
            listObjectsWork.Add(new MyClass(thisImage, (int)numericUpDownMinObjectSize.Value));
            watchAdditionalTime.Stop();
            Matrix<int> finalClusters = new Matrix<int>(thisImage.Rows * thisImage.Cols, 1);
            //бинаризация
            listObjectsWork[iCountInList].Binarization(checkBoxUsePredobrabotka.Checked);
            dTimeBinarization = listObjectsWork[iCountInList].watchBinarization.Elapsed.TotalSeconds;//время бинаризации
            
            //найти контуры
            watchAdditionalTime.Start();
            listObjectsWork[iCountInList].FindCounturs();
            watchAdditionalTime.Stop();
 
            pictureBox2.Image = listObjectsWork[iCountInList].imgBinarized.ToBitmap();
 
 
            if (Directory.Exists(textBoxWorkFolder.Text) == false)
            {
                Directory.CreateDirectory(textBoxWorkFolder.Text);
            }
            if (Directory.Exists(textBoxWorkFolder.Text + strOnlyfileName) == false)
            {
                Directory.CreateDirectory(textBoxWorkFolder.Text + strOnlyfileName);
            }
            //Directory.CreateDirectory(textBoxWorkFolder.Text);
 
            //получить пиксели только объектов
            ParallelOptions options = new ParallelOptions
            {
                MaxDegreeOfParallelism = iThreads
            };
            watchSegments.Reset();
            watchSegments.Start();
            //сегментация
            Parallel.For(0, listObjectsWork[iCountInList].listRect.Count, options, ProcessObjectList);
            watchSegments.Stop();
 
            watchPirson.Reset();
           watchPirson.Start();
           Parallel.For(0, listObjectsWork[iCountInList].listRect.Count, options, GetPirsonForParallel);
            watchPirson.Stop();
 
           try
           {
               string strFolder = textBoxWorkFolder.Text + strOnlyfileName;
               if (checkBoxSeveResults.Checked)
               {
                   for (int index = 0; index < listObjectsWork[iCountInList].listRect.Count; index++)
                   {
                       MyFilesWork.Save_jpg(index, strFolder, listObjectsWork[iCountInList].allObjects[index].imgObject, listObjectsWork[iCountInList].allObjects[index].imgSegmentedObject);
                       MyFilesWork.Save_txt(index, strFolder, listObjectsWork[iCountInList].allObjects[index].detailes.strSegmentsColorsAndS);
                   }
               }
           }
           catch
           {
           }
            dTimeAdditional = watchAdditionalTime.Elapsed.TotalSeconds;
            dTimeSegmentation = watchSegments.Elapsed.TotalSeconds;
            dTimeGetPirsonForParallel = watchPirson.Elapsed.TotalSeconds;
 
            strForReturnTemp.dTime = dTimeAdditional + dTimeSegmentation + dTimeGetPirsonForParallel + dTimeBinarization / _dBinarizationCoefficients[iThreads];
            strForReturnTemp.iSize = thisImage.Cols * thisImage.Rows;
            strForReturnTemp.iThreads = iThreads;
            
            //сохранение времени работы всей системы
            BigStruct.allSystemRealTime.dTime = strForReturnTemp.dTime;
            BigStruct.allSystemRealTime.iSize = strForReturnTemp.iSize;
            BigStruct.allSystemRealTime.iThreads = iThreads;
 
            double dAmdals = 0;
 
            //далее следует сохранить время по Амдалсу
            //если 1 поток тогда рассчитываем данные сами
            if (iThreads == 1)
            {
                dAlpha = dTimeAdditional*1.01 / BigStruct.allSystemRealTime.dTime;//доля, которая может быть получена только последовательными вычислениями
                dAmdals = 1.0 / (dAlpha + (1.0 - dAlpha) * 1.0 / iThreads);
                BigStruct.dAlpha = dAlpha;//сохраним значение Альфа
            }
            //если 2 потока тогда на основании существующих данных
            else
            {
                dAlpha = dAlphaParam;
                dAmdals = 1.0 / (dAlpha + (1.0 - dAlpha) * 1.0 / iThreads);
            }
            BigStruct.allSystemAmdals.dTime = dAmdals;
            BigStruct.allSystemAmdals.iSize = strForReturnTemp.iSize;
            BigStruct.allSystemAmdals.iThreads = iThreads;
            
            //далее сохраним время сегментации
            BigStruct.allSegmentation.dTime = dTimeSegmentation;
            BigStruct.allSegmentation.iSize = strForReturnTemp.iSize;
            BigStruct.allSegmentation.iThreads = iThreads;
 
            //далее сохраним время Пирсона
            BigStruct.allPirson.dTime = dTimeGetPirsonForParallel;
            BigStruct.allPirson.iSize = strForReturnTemp.iSize;
            BigStruct.allPirson.iThreads = iThreads;
 
            return BigStruct;
        }
Самый тяжелый участок кода здесь. Тут 99% всех вычислений.
C#
1
2
3
4
watchSegments.Start();
            //сегментация
            Parallel.For(0, listObjectsWork[iCountInList].listRect.Count, options, ProcessObjectList);
            watchSegments.Stop();
Не могу понять одну вещь.У меня есть цикл по потокам в функции getTotalTimeAllThreads.
Когда я пишу:
C#
1
for (int i = 1; i <= iThreadsMax; i++)
то при 1 потоке система отрабатывает за 132 секунды, при 2 потоках за 138 при 3 потоках за 156, при 4 потоках за 216 и так далее.
если же я напишу цикл вот так:
C#
1
for (int i = 1; i <= iThreadsMax; i++)
то при 2 потоках у меня за 75 секунд отработает, при 3 за 105 и так далее. Почему такое происходит? никак понять не могу
0
Эксперт .NETАвтор FAQ
10410 / 5140 / 1825
Регистрация: 11.01.2015
Сообщений: 6,226
Записей в блоге: 34
10.10.2016, 19:40 18
Лучший ответ Сообщение было отмечено Dimarik__1 как решение

Решение

Dimarik__1,
Смотрите, у вас незначительные на первый взгляд проблемы накапливаются и приводят к тому что вы имеете.
1) Код сложный и запутанный. Например один метод OneObject - 193 строки невнятных вычислений. 193 строки! Are you seriously? Считается хорошим тоном иметь не более 30 строк в методе. (ну и кроме того, наименование метода OneObject - неправильное)
2) У вас подозрительно много вызовов GC.Collect(). Это наталкивает на нехорошие мысли: во-первых, потому что явный вызов GC.Collect() - обычно не требуется и не приветствуется, как вредный для здоровья, во-вторых, это пахнет тем, что у вас идет перерасход памяти и вы пытаетесь его "починить" вызовом GC.Collect().
3) И точно. При запуске расчетов, видно, что у вас расход памяти программой идет на сотни мегабайт, в то время как решается довольно простая задача, и совершенно непонятно зачем там столько памяти. Почему? Потому что вы очень неоптимально используете память. Давайте посмотрим на вот этот метод:
Кликните здесь для просмотра всего текста
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
        //получить энтропию множества
        public static double GetEntropy(Matrix<float> listSource)
        {
            double dResult = 0;
 
            //размер массива
            int iLength = listSource.Data.GetLength(0); 
            
 
             int iRed = 0, iGreen = 0, iBlue = 0;
            double[, ,] dProbabilityArray = new double[256, 256, 256];
 
            for (int i = 0; i < iLength; i++)
            {
                iRed = (int)listSource.Data[i, 0];
                iGreen = (int)listSource.Data[i, 1];
                iBlue = (int)listSource.Data[i, 2];
                dProbabilityArray[iRed, iGreen, iBlue]++;
            }
            for (int i = 0; i < 256; i++)
            {
                for (int j = 0; j < 256; j++)
                {
                    for (int k = 0; k < 256; k++)
                    {
                        //если нет ни одногой точки с заданными пикселями, то не учитываем эту нулевую вероятность
                        if (dProbabilityArray[i, j, k] < 1)
                        {
                            continue;
                        }
                        dProbabilityArray[i, j, k] = dProbabilityArray[i, j, k] / iLength;
                        dResult += dProbabilityArray[i, j, k] * Math.Log(dProbabilityArray[i, j, k], 2);
                    }
                }
            }
            return -dResult;
        }

Вы создаете массив double размером 256 * 256 * 256. Только этот массив займет в памяти минимум 134 MB! И главное зачем он? Вы всего лишь пытаетесь посчитать энтропию? С ценой 134MB? OMG. Ведь есть же Dictionary<>, и ваш метод можно переписать вот так с малым (относительно) расходом памяти (и который кстати будет работать на порядки быстрее, поскольку в нем нет трехэтажных вложенных циклов):
Кликните здесь для просмотра всего текста
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
        //получить энтропию множества
        public static double GetEntropy(Matrix<float> listSource)
        {
            double dResult = 0;
 
            //размер массива
            int iLength = listSource.Data.GetLength(0);
 
            var dProbabilityArray = new Dictionary<int, int>();
 
            for (int i = 0; i < iLength; i++)
            {
                var iRed = (int)listSource.Data[i, 0];
                var iGreen = (int)listSource.Data[i, 1];
                var iBlue = (int)listSource.Data[i, 2];
                var key = (iRed << 16) | (iGreen << 8) | iBlue;
                int count;
                dProbabilityArray.TryGetValue(key, out count);
                count++;
                dProbabilityArray[key] = count;
            }
 
            foreach (var pair in dProbabilityArray)
            {
                var d = (double)pair.Value/iLength;
                dResult += d*Math.Log(d, 2);
            }
 
            return -dResult;
        }

Остальные методы вероятно примерно такие-же.

4) И теперь, отвечая непосредственно на ваш вопрос, почему у вас многопоточная версия работает медленнее однопоточной. А это потому, что у вас приложение тратит время не на расчеты. Оно тратит основное время на выделения/освобождения памяти. А поскольку память вы выделяете под каждый поток отдельно, то и получается, что чем больше потоков, тем пропорционально больше памяти используется, и тем больше времени занимает работа программы. Оптимизируйте программу, особенно по памяти и все будет хорошо.
4
0 / 0 / 1
Регистрация: 27.12.2014
Сообщений: 298
10.10.2016, 20:05  [ТС] 19
Спасибо. Очень понятно ответили. С памятью буду разбираться.Но есть ещё 1 вопрос:
1. Вот у меня имеется цикл по потокам, где я хочу оценить, за какое время у меня отработает алгоритм при разном распараллеливании:
C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
for (int i = 1; i <= iThreadsMax; i++)
            {
                GC.Collect();
                if (i == 0)
                {
                   bigData = getTotalTimeOneThread(src, strOnlyfileName, i, 0);
                }
                else
                {
                    bigData = getTotalTimeOneThread(src, strOnlyfileName, i, bigData.dAlpha);
                }
                allSystemReal.Add(bigData.allSystemRealTime);
                allSystemAmdals.Add(bigData.allSystemAmdals);
                allSystemSegmentation.Add(bigData.allSegmentation);
                allSystemPirson.Add(bigData.allPirson);
 
 
            }
Если я напишу: for (int i = 1; i <= iThreadsMax; i++)
то при i = 1 отработает за 132 сек, при i = 2 за 138, при i = 3 за 156.
А если я напишу
for (int i = 2; i <= iThreadsMax; i++)
то при i = 2 отработает за 75 секунд.
Как это может быть объяснено? Ведь память уже очищена первым операторов в цикле и внутри она нигде дополнительно не очищается. или очищается?
0
.NET senior
440 / 358 / 137
Регистрация: 23.09.2016
Сообщений: 980
10.10.2016, 22:10 20
Цитата Сообщение от Dimarik__1 Посмотреть сообщение
память уже очищена первым операторов в цикле
Dimarik__1, это очень глубокое заблуждение. При вызове GC.Collect память вот так с пол-пинка магическим образом не освобождается. Скорее это можно интерпретировать как "уважаемый Сборщик Мусора, пожалуйста, когда ты в ближайшее время будешь свободен, попробуй освободить хотя бы немножко памяти среди этой кучи байт".
0
10.10.2016, 22:10
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
10.10.2016, 22:10
Помогаю со студенческими работами здесь

Параллельное программирование - слишком большое ускорение
Если использовать параллельное программирование, при переходе от 1 потока к 2 потокам возможно...

Параллельное программирование для ускорения обработки информации
Мне необходимо выполнить бинаризацию изображения с использованием k-means на 2 кластера. Делаю я...

Параллельное программирование:Построить вектор, элементы которого равны произведению соответствующих элементов
Уважаемые программисты,буду весьма признателен, если напишите код программы на C# к данной задаче:...

Вычислить евклидову норма вектора. Используя класс Task или Parallel. Параллельное программирование
Народ помогите!!!


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
20
Ответ Создать тему
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru