PLINQ in .NET

PLINQ (Parallel LINQ) is a parallel implementation of the LINQ. PLINQ was introduced in the .NET Framework 4.0.  It provides facility to query on IEnumerable or IEnumerable<T> data source data source in a type-safe manner. PLINQ internally separates the given object and performs the operation in multiple threads on different cores.

PLINQ can be implemented just by adding AsParallel()to the data source while querying . When PLINQ process any object on that time it try to make full use of the cores which is present in the system. AS PLINQ performs the operation parallel, so in most of the cases it increases the performance but in some of the cases this assumption is fail.

Note-

Don’t use PLINQ for small processing, if you have heavy logic to implement over each element then only go for PLINQ otherwise it may be possible that performance will be poor compare to normal LINQ.

Now to understand PLINQ functionality check the below listing-

1. Performance of LINQ and PLINQ

I have written some code snippet to check the performance of LINQ and PLINQ queries. This easy implementation will explore about PLINQ performance.   

//List of string to test the application
List<string> lstNumbers = new List<string>();

private void frmPLINQ_Load(object sender, EventArgs e)
         {
             //Filling list with items
            for (long i = 0; i < 100; i++)
             {
                 lstNumbers.Add(i.ToString());
             }
        }

  //Method to process the items (Expensive method- to make is expensive I have used Thread.Sleep(100))
        private string GetItem(string item)
        {
            System.Threading.Thread.Sleep(100);
            return "Item_"+item  ;
        }

//Code to process list item using normal LINQ
       private void btnLINQ_Click(object sender, EventArgs e)
        {
             try
            {
                 //Stop watch to measure the performance
                Stopwatch sw = new Stopwatch();
                 sw.Start();

                var result = (from item in lstNumbers
                               select item = GetItem(item)).ToList();

                sw.Stop();
                lblLINQ.Text = sw.ElapsedMilliseconds.ToString() + " (ms)";
            }
            catch (Exception ex)
             {
                 MessageBox.Show(ex.Message);
             }
         }


Output-  1000(ms)

        //Code to process list item using normal LINQ
        private void btnPLINQ_Click(object sender, EventArgs e)
        {
             try
            {
                 //Stop watch to measure the performance
                Stopwatch sw = new Stopwatch();
                 sw.Start();

                 //Parallel processing of items using AsParallel()
                var result = (from item in lstNumbers.AsParallel()
                               select item = GetItem(item)).ToList();

                sw.Stop();
                lblPLINQ.Text = sw.ElapsedMilliseconds.ToString() + " (ms)";
            }
            catch (Exception ex)
             {
                 MessageBox.Show(ex.Message);
             }
         }

Output-  2585(ms)

In above code I have written same code for both buttons only the difference is AsParallel() method which is written for PLINQ implementation.





You can see above snap to find out the performance of LINQ and PLINQ is. AS we can see that PLINQ performance is better than LINQ.

2. PLINQ Degree of Parallelism

While implementing PLINQ we can set Degree of Parallelism to process the items, if we will not set then .NET Framework will automatically take care of this. To set Degree of Parallelism we can use - WithDegreeOfParallelism() method. Based on this value PLINQ performance will be reflected.

The main motto of setting this value is that - restrict the maximum number of thread to run concurrently.
Now check the below code snippets-

//Setting degree of parallelism using WithDegreeOfParallelism =1
                var result = (from item in lstNumbers.AsParallel().WithDegreeOfParallelism (1)
                              select item = GetItem(item)).ToList();

Output- 1000(ms)

//Setting degree of parallelism using WithDegreeOfParallelism=2
                var result = (from item in lstNumbers.AsParallel().WithDegreeOfParallelism(2)
                              select item = GetItem(item)).ToList();

Output- 5000(ms)





As we can see that,

for WithDegreeOfParallelism (1) elapsed time is – 1000 ms And
for WithDegreeOfParallelism (2) elapsed time is – 5000 ms

Which indicates that WithDegreeOfParallelism() reflect the PLINQ performance.

We can set max value for it as 64. It this value will be greater than 64 then it will throw error-
Error-
Specified argument was out of the range of valid values.
Parameter name: degreeOfParallelism

3. PLINQ with CancellationToken

It may be possible that after starting the process we want to stop or cancel the execution of PLINQ then we can set CancellationToken for it which will allow us to cancel the operation. For this we pass CancellationToken to WithCancellation() method. To explore this I have written some code snippets, check the below code-

I have created the object of CancellationTokenSource class and while processing the items in have passed its token to WithCancellation() method.

//Code to process list item using PLINQ with CancellationToken
        CancellationTokenSource cancellationTokenSource= new CancellationTokenSource();
        private void btnCancellationToken_Click(object sender, EventArgs e)
         {
             try
            {
                 //Stop watch to measure the performance
                Stopwatch sw = new Stopwatch();
                 sw.Start();

                 //Processing items with WithCancellation()
                var result = (from item in lstNumbers.AsParallel().WithCancellation(cancellationTokenSource.Token)
                              select item = GetData(item)).ToList();

                sw.Stop();
                lblCancellationToken.Text = sw.ElapsedMilliseconds.ToString() + " (ms)";
            }
            catch (OperationCanceledException ex)
            {
                lblCancellationToken.Text = "Operation cancelled...";
                 MessageBox.Show("Operation cancelled... " + ex.Message);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

I have written this method to handle the cancellation of operation. I am cancelling the opearation using Cancel () method based on if cobdition. If item value will be “55” then operation will be cancelled.

        //Method to process the items with cancellationToken
        private string GetData(string item)
        {
            //If item value is '55' then cancelling
            if (string.Equals(item, "55"))
            {
                 cancellationTokenSource.Cancel();
            }
            //Checking for cancellation request
            if (cancellationTokenSource.Token.IsCancellationRequested)
             {
                 return "";
            }
            System.Threading.Thread.Sleep(100);
            return "Item_" + item;
        }

In above code once the value of item will be “55” then operation will be cancelled, to handle it, I have written separate catch block using OperationCanceledException exception class which will handle cancellation of operation.

4. PLINQ with AsOrdered

As PLINQ run multiple threads concurrently, so there is no guarantee of ordered processing. If we want to process the item in ordered then we can use AsOrdered(). Check the below snippets-

//Processing the list with AsOrdered()
                var result = (from item in lstNumbers.AsParallel().AsOrdered ()
                              select item = GetItem(item)).ToList();

Items will be in ordered after processing.

5. Exception handling in PLINQ

While querying the items using PLINQ it may be possible that it will generate exceptions, these all exception can be tracked by System.AggregateException class. Check the blow code snippet-

try
    {
         //Code to process items using PLINQ
    }

    catch (AggregateException e)
    {
        foreach (var ex in e.InnerExceptions)
        {
            MessageBox.Show(ex.Message);
        }
    }

Using all these listing we can implement the PLINQ. While implementing the PLINQ there are some points which will help us to speed up the performance. Check the blow link

To speedup-

http://msdn.microsoft.com/en-us/library/dd997399%28v=vs.110%29.aspx

You can download complete code snippets from here-

PLINQ



By Jitendra Faye   Popularity  (1967 Views)