parallel operations. How make them quickly?

Dimarik_1

Member
Joined
Oct 9, 2016
Messages
6
Programming Experience
1-3
I want to make my code quickly. I have got 8 cores. And I want use all of them. How can I do this in optimal way? I think than I can do this in 2 ways:
1. Make short functions. And parallel them. But I think that there will be many time for give management transmission from one core to another. Am I right? I think that make very short operations like ?a = 2 + 2? is time, which will be expend for management transmission from one core to another will be more than speed increment by use parallel operations. Am I right?
2. Make big functions. I think if every function have long operation, parallel effect will be better.
But I made experiments and in fact first way is more quickly that second. Why the first way is more quickly and how can I do this code more quick by using parallel operations?

C#:
[B]using[/B] System;
[B]using[/B] System.Collections.Generic;
[B]using[/B] System.ComponentModel;
[B]using[/B] System.Data;
[B]using[/B] System.Drawing;
[B]using[/B] System.Linq;
[B]using[/B] System.Text;
[B]using[/B] System.Threading.Tasks;
[B]using[/B] System.Windows.Forms;
[B]using[/B] System.Diagnostics;
[B]using[/B] System.Threading;
[B]namespace[/B] WindowsFormsApplication2
{
    [B]public[/B] [B]partial[/B] [B]class[/B] Form1 : Form
    {
        [B]public[/B] Form1()
        {
            InitializeComponent();
        }
        [B]double[/B] [] _dArray = new [B]double[/B][10000000];
        [B]double[/B][] _dArray2 = new [B]double[/B][10000000];
        [B]int[/B] _iThreads = 8;
        [B]int[/B] _iSizeBlock;
 
        [B]private[/B] [B]void[/B] button1_Click([B]object[/B] sender, EventArgs e)
        {
            _iSizeBlock = _dArray.Length / _iThreads;[I]//size of block[/I]
           
            [I]//[/I][I]random[/I]
            Random r = new Random();
            [B]for[/B] ([B]int[/B] i = 0; i < _dArray.Length; i++)
            {
                _dArray[i] = r.NextDouble();
                _dArray2[i] = _dArray[i];
            }
             richTextBox1.Text = "1 interation:[B]\r\n[/B]";
             [B]for[/B] ([B]int[/B] i = 1; i <= 8; i++)
             {
                 ParallelOptions options = new ParallelOptions
            {
                MaxDegreeOfParallelism = i
            };
                 Stopwatch st1 = new Stopwatch();
                 st1.Start();
                 Parallel.[B]For[/B](0, _dArray.Length, options, parallelOne);
                 st1.Stop();
                 richTextBox1.Text += i.ToString() + " threads, time: " + st1.Elapsed.TotalSeconds.ToString() + "[B]\r\n[/B]";
             }
 
             richTextBox1.Text += "Iterations block:[B]\r\n[/B]";
             [B]for[/B] ([B]int[/B] i = 1; i <= 8; i++)
             {
                 ParallelOptions options = new ParallelOptions
                 {
                     MaxDegreeOfParallelism = i
                 };
                 Stopwatch st1 = new Stopwatch();
                 st1.Start();
                 Parallel.[B]For[/B](0, i, options, ParallelBlock);
                 st1.Stop();
                 richTextBox1.Text += i.ToString() + " threads, time: " + st1.Elapsed.TotalSeconds.ToString() + "[B]\r\n[/B]";
             }
           
        }
       
        [B]private[/B] [B]void[/B] ParallelBlock([B]int[/B] iIndex)
        {
            [B]int[/B] iStart = iIndex * _iSizeBlock;
            [B]int[/B] iEnd = iStart + _iSizeBlock;
            [I]//iIndex ? number Of Block[/I]
            [B]for[/B] ([B]int[/B] i = iStart; i < iEnd; i++)
            {
                _dArray[i] = Someoperations(_dArray[i]);
            }
        }
        [B]private[/B] [B]void[/B] parallelOne([B]int[/B] iIndex)
        {
            _dArray[iIndex] = Someoperations(_dArray[iIndex]);
        }
        [B]private[/B] [B]double[/B] Someoperations([B]double[/B] dInput)
        {
            [B]double[/B] 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);
            [B]return[/B] Result;
        }
    }

Results:[FONT=&quot]1 iteration:
1 threads, time: 2,5947303
2 threads, time: 1,5046816
3 threads, time: 1,2435103
4 threads, time: 1,1743574
5 threads, time: 1,8177255
6 threads, time: 1,8564871
7 threads, time: 1,7038264
8 threads, time: 1,7404472
Iteration block:
1 threads, time: 1,2824387
2 threads, time: 1,2592897
3 threads, time: 1,3303499
4 threads, time: 1,3710368
5 threads, time: 1,4195757
6 threads, time: 1,4460356
7 threads, time: 1,5213963
8 threads, time: 1,6072681
[/FONT]
 
When running your example I get best result when MaxDegreeOfParallelism is not set (-1), which is the general advice in help: ParallelOptions.MaxDegreeOfParallelism Property (System.Threading.Tasks)

Also, you should read this: Potential Pitfalls in Data and Task Parallelism
"Avoid Executing Parallel Loops on the UI Thread", if you look at ManagedThreadId you'll see much of your operations are done in UI thread.
"Do Not Assume that Iterations of ForEach, For and ForAll Always Execute in Parallel", again looking at ManagedThreadId you'll see same thread is reused often especially for parallelOne (I see long series of same thread being used).
 
Thank you. I have read manual.
Can you write some example to make function SomeOperations which I wrote for double [] _dArray = new double[10000000] in parallel? I need very high speed. Thank you
 
Parallel.For with parallelOne is the faster in my tests, with default MaxDegreeOfParallelism. Just be sure to start the processing off a task (background thread) to ensure Parallel.For doesn't use the UI thread also.
 
I think that MaxDegreeOfParallelism shuold be equal Environment.ProcessorCount.
Why parallelOne is the faster? Do you know? I think that parallelOne should not be faster bacause it spend a lot of time for function call many times. Do you agree?
You wrote:
"
Just be sure to start the processing off a task (background thread) to ensure Parallel.For doesn't use the UI thread also.​


  • "
    How can I do this?
 
I have been found this code in the Internet:
C#:
[COLOR=#2B91AF]Thread[/COLOR][COLOR=#303336].[/COLOR][COLOR=#2B91AF]BeginThreadAffinity[/COLOR][COLOR=#303336]();[/COLOR][COLOR=#303336]
                        [/COLOR][COLOR=#101094]foreach[/COLOR][COLOR=#303336]([/COLOR][COLOR=#2B91AF]ProcessThread[/COLOR][COLOR=#303336] pt [/COLOR][COLOR=#101094]in[/COLOR][COLOR=#303336] [/COLOR][COLOR=#2B91AF]Process[/COLOR][COLOR=#303336].[/COLOR][COLOR=#2B91AF]GetCurrentProcess[/COLOR][COLOR=#303336]().[/COLOR][COLOR=#2B91AF]Threads[/COLOR][COLOR=#303336])[/COLOR][COLOR=#303336]
            [/COLOR][COLOR=#303336]{[/COLOR][COLOR=#303336]
                [/COLOR][COLOR=#2B91AF]int[/COLOR][COLOR=#303336] utid [/COLOR][COLOR=#303336]=[/COLOR][COLOR=#303336] [/COLOR][COLOR=#2B91AF]GetCurrentThreadId[/COLOR][COLOR=#303336]();[/COLOR][COLOR=#303336]
                [/COLOR][COLOR=#101094]if[/COLOR][COLOR=#303336] [/COLOR][COLOR=#303336]([/COLOR][COLOR=#303336]utid [/COLOR][COLOR=#303336]==[/COLOR][COLOR=#303336] pt[/COLOR][COLOR=#303336].[/COLOR][COLOR=#2B91AF]Id[/COLOR][COLOR=#303336])[/COLOR][COLOR=#303336]
                [/COLOR][COLOR=#303336]{[/COLOR][COLOR=#303336]
                    pt[/COLOR][COLOR=#303336].[/COLOR][COLOR=#2B91AF]ProcessorAffinity[/COLOR][COLOR=#303336] [/COLOR][COLOR=#303336]=[/COLOR][COLOR=#303336] [/COLOR][COLOR=#303336]([/COLOR][COLOR=#2B91AF]IntPtr[/COLOR][COLOR=#303336])([/COLOR][COLOR=#303336]_iCPUThread[/COLOR][COLOR=#303336]);[/COLOR][COLOR=#303336] [/COLOR][COLOR=#858C93]// Set affinity for this[/COLOR][COLOR=#303336]
                    [/COLOR][COLOR=#2B91AF]AllIterations[/COLOR][COLOR=#303336]();[/COLOR][COLOR=#303336]
                [/COLOR][COLOR=#303336]}[/COLOR][COLOR=#303336]
            [/COLOR][COLOR=#303336]}[/COLOR][COLOR=#303336]
            [/COLOR][COLOR=#2B91AF]Thread[/COLOR][COLOR=#303336].[/COLOR][COLOR=#2B91AF]EndThreadAffinity[/COLOR][COLOR=#303336]();[/COLOR]
May be it will be faster than Parallel.For?
I think that in my code with Parallel.For ParallelBlock works in one core many times. For example, I have got 12 cores. I make Parallel.for in 12 threads and 4 threads make on first core, 5 threads on second core and other on third core. Am I right?
 
I have made another experiment.
Please, tell my, why cycle for is faster then Parallel.For?
C#:
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
 
You have swapped stopwatch times.

Even without parallel you can't do this kind of thing on UI thread.
 
You wrote:
"
Just be sure to start the processing off a task (background thread) to ensure Parallel.For doesn't use the UI thread also.



  • "
    How can I do this?
 
You can use any way to start a new thread, for example Task.Run. There's also example in the "Pitfalls" article that I adviced you to read in section "Avoid Executing Parallel Loops on the UI Thread".
 
Yes, you want to run the Parallel.ForEach on a separate Task or Worker thread to keep the UI thread unblock. This is because the Parallel.Foreach will block the current thread until its done.

I am currently creating a 3-Part series Youtube video regarding the Parallel.Foreach topic, where I talk about issues regarding blocking the UI thread and comparisons of the For loop vs Parallel.Foreach to make it run faster! I also discuss four cancellation scenarios in part#2. I suggest checking it out, it might help you out. https://www.youtube.com/watch?v=uxuDI-LQnnI
 
Back
Top Bottom