[Home] Edit Article
Author Information
File Uploads
Edit Article XML Content
<?xml version="1.0"?> <document> <header> <issuecode> </issuecode> <articlecode> </articlecode> <zone> </zone> <title>Declarative Data Parallelism Using Parallel LINQ</title> <authors> <author> <name>Joydip Kanjilal</name> <bio> <p>Joydip Kanjilal is a Microsoft Most Valuable Professional in ASP.NET. He is also a speaker and author of several books and articles. He has over 14 years of industry experience in IT with more than 8 years in Microsoft .NET and its related technologies. He was selected as MSDN Featured Developer of the Fortnight (MSDN) a number of times and also as Community Credit Winner at www.community-credit.com several times. Joydip has authored the following books:-</p> <p> </p> <p>ASP.NET 4.0 Programming (Mc-Graw Hill Publishing)</p> <p>Entity Framework Tutorial (Packt Publishing)</p> <p>Pro Sync Framework (APRESS)</p> <p>Sams Teach Yourself ASP.NET Ajax in 24 Hours (Sams Publishing)</p> <p>ASP.NET Data Presentation Controls Essentials (Packt Publishing)</p> <p> </p> <p>Joydip has authored more than 200 articles for some of the most reputable sites like, www.msdn.microsoft.com, www.asptoday.com, www.devx.com, www.ddj.com, www.aspalliance.com, www.aspnetpro.com, www.sql-server-performance.com, www.sswug.com, etc. A lot of these articles have been selected at www.asp.net - Microsoft’s official site on ASP.NET.</p> <p>Joydip is currently working as an independent software consultant and author. He has years of experience in designing and architecting solutions for various domains. His technical strengths include, C, C++, VC++, Java, C#, Microsoft .NET, Ajax, WCF, REST, SOA, Design Patterns, SQL Server, Operating Systems and Computer Architecture.</p> <p>Joydip blogs at: http://aspadvice.com/blogs/joydip and spends most of this time writing books and articles. When not at work, Joydip spends his time with his family, playing chess and watching cricket and soccer.</p> <p>MVP Profile: https://mvp.support.microsoft.com/default.aspx/profile/joydip</p> </bio> <photo>UNKNOWNIMAGE</photo> </author> </authors> <copyright>2010 - CoDe Magazine and EPS Software Corp.</copyright> <owner>CoDe Magazine</owner> </header> <body> <p id="1">Applications can be single threaded or multithreaded. A single-threaded application is one in which the processor executes threads in a sequence, i.e., a thread would be scheduled by the operating system only if the execution of the currently running thread is complete. This approach doesn’t provide much system throughput (a measure of the amount of work done in unit time).</p> <p id="2">In contrast, a multithreaded application is one in which multiple threads reside in memory at the same point in time with one of them in execution state. In such applications, a thread needn’t wait for the turnaround time of the executing thread to be complete for it to be scheduled - threads are preempted and scheduled by the operating system according to their priorities. So, you have more throughput in such applications than you can expect in single threaded applications. Moreover, single threaded applications cannot take advantage of today’s multi-core systems. With a view to leverage the benefits of the multi-core systems, support for parallel programming has been included in .NET Framework.</p> <p id="3">Microsoft’s Parallel LINQ (PLINQ) is a concurrency execution engine for executing LINQ queries. It is a part of the managed concurrency library called Parallel Extensions Library (previously known as Parallel Framework Extensions or PFX). This article explores parallel programming concepts, PLINQ, discusses the new features and enhancements to the Parallel Extensions Library, and shows you how to implement declarative data parallelism in your applications using PLINQ. It also discusses how you can handle concurrency exceptions, the guidelines and best practices in using PLINQ in enterprise applications and tips for improving the performance of PLINQ queries.</p> <h2>Prerequisites</h2> <p id="4">To work with the code examples illustrated in this article, you should have one of the following installed in your system:</p> <list type="bulleted"> <bulletedlist>Visual Studio 2008 with the Parallel Extensions Library</bulletedlist> <bulletedlist>Visual Studio 2010</bulletedlist> </list> <h2>Concurrency and Parallelism - How Do They Differ?</h2> <p id="5">Concurrency and parallelism are two distinctly different concepts. Let’s consider a scenario in which two tasks, TaskA and TaskB, are to be executed concurrently. Now, TaskA and TaskB are concurrent if one of the following is true:</p> <list type="numbered"> <numberedlist>Either of the two tasks, TaskA or TaskB, can be executed and completed before the other.</numberedlist> <numberedlist>Both tasks are executed alternatively.</numberedlist> <numberedlist>Both tasks are executed simultaneously at the same point in time (this is also known as parallelism).</numberedlist> </list> <p id="6">Note that concurrent execution of a program is possible on a single processor but parallelism is only possible on multi-core, multi-processor or distributed systems. The reason is that a single processor can at the same point in time execute one thread only. Incidentally, a thread is the path of execution within a process. In essence, parallelism is the ability to execute tasks simultaneously on different processors. This is constrained by the fact that if you need threads to be executed in parallel, you should have multi-core, multi-processor or distributed systems to execute them.</p> <p id="7">Two of the most important types of parallelism include <i>data parallelism </i>and <i>task parallelism</i>. While the former refers to the ability to distribute data across different parallel computing nodes and have threads in parallel execute the same instruction on different chunks of data, the later is the ability to execute tasks in parallel where each task may use the same or different data. In other words, task parallelism enables you to execute tasks asynchronously.</p> <h2>Parallel Extensions</h2> <p id="8">Parallel Extensions (previously known as Parallel Framework Extensions or PFX) is a managed concurrency library that provides excellent support for imperative and declarative, data and task parallelism. It is a light-weight library that allows LINQ developers to leverage the benefits of multi-core systems with full support for all .NET query operators and minimal impact to the existing LINQ model. The Parallel Extensions library comprises of a set of APIs that can be used to take advantage of multiple cores in your system and implement data parallelism and task parallelism in your applications. </p> <p id="9">The Parallel Extensions library is comprised of:</p> <list type="bulleted"> <bulletedlist>Task Parallel Library (TPL)</bulletedlist> <bulletedlist>Parallel LINQ (PLINQ)</bulletedlist> <bulletedlist> </bulletedlist> </list> <h3>The Task Parallel Library</h3> <p id="10">The Task Parallel Library is a set of APIs in the System.Threading and System.Threading.Tasks namespaces in .NET Framework 4 that helps you to implement parallelism and concurrency to your applications.</p> <p id="11">The Parallel class is a part of the TPL and is contained in the System.Threading namespace. This class contains the static methods For, ForEach and Invoke. While you can use Parallel.For and Parallel.ForEach to parallelize loops and implement imperative data parallelism in your applications, Parallel.Invoke enables you to implement task parallelism with ease.</p> <p id="12">Consider the following “for” loop that stores the squares of integers from 1 to 25 in an integer list:</p> <codesnippet> <font color="Blue">for»</font>(<font color="Blue">int»</font>i»=»0;»i»<»integerList.Count();»i++)</codesnippet> <codesnippet>»»»»»»»»»»»»{</codesnippet> <codesnippet>»»»»»»»»»»»»»»»»integerList[i]»=»(i»+»1)»*»(i»+»1);</codesnippet> <codesnippet>»»»»»»»»»»»»}</codesnippet> <p id="13">To parallelize the “for” loop using the TPL, all you have to do is use the Parallel.For method of the Parallel class as shown below:</p> <codesnippet>Parallel.For(0,»integerList.Length,»i»=>»</codesnippet> <codesnippet>integerList[i]»=»(i»+»1)»*»(i»+»1));</codesnippet> <p id="14">The IsPrime() method below accepts an integer and checks to see if the number is prime, i.e., if the number is only divisible by itself and 1. If the number is prime, the method returns true, false otherwise.</p> <codesnippet> <font color="Blue">private»static»bool»</font>IsPrime(<font color="Blue">int»</font>number)</codesnippet> <codesnippet>»»»»»»»»{</codesnippet> <codesnippet>»»»»»»»»»»»»<font color="Blue">if»</font>(number»<»2)</codesnippet> <codesnippet>»»»»»»»»»»»»»»»»<font color="Blue">return»false</font>;</codesnippet> <codesnippet> </codesnippet> <codesnippet>»»»»»»»»»»»»<font color="Blue">int»</font>limit»=»(<font color="Blue">int</font>)Math.Sqrt(number);</codesnippet> <codesnippet> </codesnippet> <codesnippet>»»»»»»»»»»»»<font color="Blue">for»</font>(<font color="Blue">int»</font>i»=»2;»i»<=»limit;»i++)</codesnippet> <codesnippet>»»»»»»»»»»»»»»»»<font color="Blue">if»</font>(number»%»i»==»0)</codesnippet> <codesnippet>»»»»»»»»»»»»»»»»»»»»<font color="Blue">return»</font>false<font color="Blue">;</font></codesnippet> <codesnippet>»»»»»»»»»»»»<font color="Blue">return»true</font>;</codesnippet> <codesnippet>»»»»»»»»}</codesnippet> <p id="15"> <b>Listing 1 </b>makes use of the IsPrime() method to display all prime numbers from 1 to 999.</p> <p id="16">Now, to parallelize the “for” loop, you just need to make a call to the Parallel.For() method. <b>Listing 2 </b>shows how this can be accomplished.</p> <p id="17">The Parallel.ForEach() method is a multithreaded implementation of the foreach loop. It enables you to iterate over a set of data.</p> <pullquote>When parallelizing loops, you should consider parallelizing only the outer loops and not the inner ones unless the outer loop’s range is small and the inner loop has a large range so as to provide enough parallelism.</pullquote> <p id="18">You can use the Parallel.Invoke() method to implement task parallelism in your applications. Suppose you have three tasks, TaskA, TaskB and TaskC that you would like to be executed in parallel. Let these three tasks be executed by the methods MethodA, MethodB and MethodC respectively. You can use the Parallel.Invoke() static method to execute these tasks in parallel as illustrated in the code snippet below:</p> <codesnippet>Parallel.Invoke(</codesnippet> <codesnippet>»»»»»»»»»»»»»»()»=>»MethodA(),</codesnippet> <codesnippet>»»»»»»»»»»»»»»()»=>»MethodB(),</codesnippet> <codesnippet>»»»»»»»»»»»»»»()»=>»MethodC());</codesnippet> <h3>Parallel LINQ</h3> <p id="19">Parallel LINQ or PLINQ as it is commonly called, is a parallel execution engine that runs on top of the managed environment of the .NET Framework and is used to execute LINQ queries on multi-core systems. It accepts LINQ to Object or LINQ to XML queries and runs them on multiple processors in your system. </p> <pullquote>Language Integrated Query (or LINQ as it is commonly called) is a query execution engine that provides a simplified framework for accessing relational data. LINQ runs on top of the managed environment of the .NET Framework and was first made available as part of .NET Framework 3.5 and Visual Studio 2008.</pullquote> <p id="20">Under the covers, PLINQ works on the principle of partitioning - it breaks the input chunk of data into pieces and distributes these pieces to the processing cores of the system. Each of these processing cores would then process the data and then the resultant set of data would then be formed by merging the results as appropriate. You can use PLINQ to build applications that can take advantage of the parallel hardware for building applications that are high performant and scalable.</p> <pullquote>In their MSDN article, “Running Queries On Multi-Core Processors” Joe Duffy and Ed Essey mention: “PLINQ is a query execution engine that accepts any LINQ-to-Objects or LINQ-to-XML query and automatically utilizes multiple processors or cores for execution when they are available.” Reference: http://msdn.microsoft.com/en-us/magazine/cc163329.aspx</pullquote> <h2>Declarative Data Parallelism Using PLINQ</h2> <p id="21">Parallel LINQ (PLINQ) is a parallel execution engine that can be used to execute LINQ queries on multi-core systems by taking advantage of parallel hardware. PLINQ provides excellent support for implementing declarative data parallelism in your applications using the ParallelEnumerable and ParallelQuery classes. Both of these classes belong to the System.Linq namespace and help you to implement declarative data parallelism in your applications. The ParallelQuery class contains two methods namely, AsParallel and AsSequential. </p> <p id="22">To parallelize your existing LINQ to Objects or LINQ to XML queries, all you have to do is:</p> <list type="bulleted"> <bulletedlist>Add a reference to the System.Concurrency.dll assembly in your application at compilation time</bulletedlist> <bulletedlist>Make a call to the System.Linq.ParallelEnumerable.AsParallel() extension method on the data</bulletedlist> </list> <p id="23">The AsParallel() extension method is defined in the PLINQ library as shown below:</p> <codesnippet> <font color="Blue">public»static»class»</font>System.Linq.ParallelEnumerable»</codesnippet> <codesnippet>»»»{</codesnippet> <codesnippet>»»»<font color="Blue">public»static»</font>IParallelEnumerable<T>»AsParallel<T>(</codesnippet> <codesnippet>»»»<font color="Blue">this»</font>IEnumerable<T>»source);</codesnippet> <codesnippet>»»»<font color="Green">//Other»Standard»Query»Operators</font></codesnippet> <codesnippet>»»»}</codesnippet> <p id="24">The AsParallel is an overloaded extension method that can accept the degree of parallelism and the ParallelQueryOptions enumeration as parameters. The degree of parallelism is given by the total number of threads in use while the parallel query is in execution. The ParallelQueryOptions enumeration can have one of the two possible values: None and PreserveOrdering.</p> <p id="25">Consider the following code snippet that uses LINQ to display integers stored in an integer list:</p> <codesnippet> <font color="Blue">int</font>[]»numList»=»<font color="Blue">new»int</font>[25];</codesnippet> <codesnippet> </codesnippet> <codesnippet>»»»»»»»»»»»»<font color="Blue">for»</font>(<font color="Blue">int»</font>i»=»0;»i»<»numList.Count();»i++)</codesnippet> <codesnippet>»»»»»»»»»»»»{</codesnippet> <codesnippet>»»»»»»»»»»»»»»»»numList[i]»=»i»+»1;</codesnippet> <codesnippet>»»»»»»»»»»»»}</codesnippet> <codesnippet> </codesnippet> <codesnippet>»»»»»»»»»»»»<font color="Blue">var»</font>result»=»(<font color="Blue">from»</font>n»<font color="Blue">in»</font>numList»<font color="Blue">select»</font>n);</codesnippet> <codesnippet> </codesnippet> <codesnippet>»»»»»»»»»»»»<font color="Blue">foreach»</font>(<font color="Blue">var»</font>x»<font color="Blue">in»</font>result)</codesnippet> <codesnippet>»»»»»»»»»»»»{</codesnippet> <codesnippet>»»»»»»»»»»»»»»»»Console.WriteLine(x);</codesnippet> <codesnippet>»»»»»»»»»»»»}</codesnippet> <p id="26">To convert the query to PLINQ, all you have to do is use the AsParallel() method as shown here:</p> <p id="27">PLINQ would parallelize the query based on the number of processing cores available in the system. The AsParallel() method would return an object of type ParallelQuery<int>. This example though not a great illustration of how you can benefit from using PLINQ in your applications, still could help you understand how to parallelize your queries using PLINQ.</p> <p id="28">The ForAll extension method in PLINQ is defined on ParallelEnumerable and works on any data of type ParallelQuery<T>. It can be used to process data returned as a result of execution of a parallel query. The following piece of code shows how ForAll() can be used:</p> <codesnippet>String[]»data»=»<font color="Blue">new»</font>String[26];</codesnippet> <codesnippet>»»»<font color="Blue">for»</font>(<font color="Blue">int»</font>index»=»65;»index»<=»90;»data[index»-»65]»=</codesnippet> <codesnippet>»»»((<font color="Blue">char</font>)index).ToString(),»index++)»;</codesnippet> <codesnippet>»»»<font color="Blue">var»</font>result»=»<font color="Blue">from»</font>x»<font color="Blue">in»</font>data.AsParallel()»<font color="Blue">select»</font>x;</codesnippet> <codesnippet>»»»result.ForAll(q»=>»Console.WriteLine(q));</codesnippet> <p id="29"> <b>Listing 3 </b>is the PLINQ version of <b>Listing 2 </b>- it shows how you can display prime numbers from 1 to 999 using PLINQ.</p> <p id="30">To find the time elapsed to execute the parallel query, you can make use of the Stopwatch class. <b>Listing 4 </b>shows how you can do this.</p> <h2>Analyzing PLINQ Performance</h2> <p id="31">In this section we will write a program that would illustrate the performance differences between a LINQ and a PLINQ query. The program would display prime numbers between 1 to 999999 both using LINQ and PLINQ.</p> <p id="32">The GetTimeElasped() method shown below would return the time taken to execute an action.</p> <codesnippet> <font color="Blue">private»static»</font>TimeSpan»GetTimeElasped(Action»action)</codesnippet> <codesnippet>»»»{</codesnippet> <codesnippet>»»»»»»»Stopwatch»stopWatch»=»<font color="Blue">new»</font>Stopwatch();</codesnippet> <codesnippet>»»»»»»»stopWatch.Start();</codesnippet> <codesnippet>»»»»»»»action();</codesnippet> <codesnippet>»»»»»»»<font color="Blue">return»</font>stopWatch.Elapsed;</codesnippet> <codesnippet>»»»}</codesnippet> <p id="33">The following code snippet shows how the IsPrime() method can be called, once using LINQ and then using PLINQ query. The prime numbers would be stored in a Dictionary. We needn’t display the primes - we have done it already earlier. We would just need to retrieve the difference in the time taken for both these approaches.</p> <codesnippet> <font color="Blue">for»</font>(<font color="Blue">int»</font>index»=»0;»index»<»5;»index++)</codesnippet> <codesnippet>»»»»»»»{</codesnippet> <codesnippet>»»»»»»»»»»Console.WriteLine("Concurrent»Execution:»"»+</codesnippet> <codesnippet>»»»»»»»»»»»»»»»»»»GetTimeElasped(<font color="Blue">delegate</font></codesnippet> <codesnippet>»»»»»»»{</codesnippet> <codesnippet>»»»»»»»»»»<font color="Blue">var»</font>dictionary»=»(<font color="Blue">from»</font>i»<font color="Blue">in»</font></codesnippet> <codesnippet>»»»»»»»»»»»»»»»»»»»»»»»»»»»»Enumerable.Range(0,»999999)</codesnippet> <codesnippet>»»»»»»»»»»»»»»»»»»»»»»»»»»»»<font color="Blue">where»</font>IsPrime(i)»</codesnippet> <codesnippet>»»»»»»»»»»»»»»»»»»»»»»»»»»»»<font color="Blue">select»</font>i).ToDictionary(i»=></codesnippet> <codesnippet>»»»»»»»»»»»»»»»»»»»»»»»»»»»»i);</codesnippet> <codesnippet>»»»»»»»}));</codesnippet> <codesnippet> </codesnippet> <codesnippet>»»»»»»»»»»Console.WriteLine("Parallel»Execution:»"»+»</codesnippet> <codesnippet>»»»»»»»»»»»»»»»»»»GetTimeElasped(<font color="Blue">delegate</font></codesnippet> <codesnippet>»»»»»»»{</codesnippet> <codesnippet>»»»»»»»»»»<font color="Blue">var»</font>dict»=»(<font color="Blue">from»</font>i»<font color="Blue">in»</font>Enumerable.Range(0,»</codesnippet> <codesnippet>»»»»»»»»»»»»»»»»»»»»»»999999).AsParallel()»</codesnippet> <codesnippet>»»»»»»»»»»»»»»»»»»»»»<font color="Blue">where»</font>IsPrime(i)»</codesnippet> <codesnippet>»»»»»»»»»»»»»»»»»»»»»<font color="Blue">select»</font>i).ToDictionary(i»=>»i);</codesnippet> <codesnippet>»»»»»»»}));</codesnippet> <codesnippet>»»»»»»»}</codesnippet> <pullquote>The Visual Studio 2010 IDE now comes with excellent support for debugging, profiling and analyzing applications that make use of parallel programming. You now have the Parallel Stacks Window that gives you the call stack information of all running threads and tasks at any given point in time and the Parallel Tasks Window that gives you all related information about a task, i.e., the task ID, the entry point, and the thread to which the task has been assigned, state information and the current location of the task.</pullquote> <p id="34"> <b>Listing 5 </b>shows the complete source code of this program. When you execute the program, the output would look similar to <b>Figure 1</b>. As you can see, the PLINQ version of the query runs much faster. </p> <h2>Preserving the Order of Data</h2> <codesnippet> <font color="Blue">int</font>[]»numList»=»<font color="Blue">new»int</font>[25];</codesnippet> <codesnippet> </codesnippet> <codesnippet>»»»»»»»<font color="Blue">for»</font>(<font color="Blue">int»</font>i»=»1;»i»<=»numList.Count();»i++)</codesnippet> <codesnippet>»»»»»»»{</codesnippet> <codesnippet>»»»»»»»»»»»numList[i»-»1]»=»i;</codesnippet> <codesnippet>»»»»»»»}</codesnippet> <codesnippet> </codesnippet> <codesnippet>»»»»»»»<font color="Blue">int</font>[]»resultSet»=»(<font color="Blue">from»</font>x»<font color="Blue">in»</font></codesnippet> <codesnippet>»»»»»»»»»»»»»»»»»»»»»»»»»»numList.AsParallel()</codesnippet> <codesnippet>»»»»»»»»»»»»»»»»»»»»»»»»»»<font color="Blue">select»</font>x»*»x).ToArray();</codesnippet> <codesnippet> </codesnippet> <codesnippet>»»»»»»»<font color="Blue">for»</font>(<font color="Blue">int»</font>index»=»0;»index»<»resultSet.Length;»</codesnippet> <codesnippet>»»»»»»»»»»»»index++)</codesnippet> <codesnippet>»»»»»»»{</codesnippet> <codesnippet>»»»»»»»»»»»Console.WriteLine(resultSet[index]);</codesnippet> <codesnippet>»»»»»»»}</codesnippet> <p id="35">When this piece of code is executed, the obvious result should be that it would display the squares of integers from 1 to 25 sequentially. However, because PLINQ executes the query in parallel, the ordering may not be preserved in this sequence. If you were to preserve the ordering of the data displayed, i.e., if you would like to have the display of the integers in the sequence stated above, you would have to pass QueryOptions.PreserveOrdering as a parameter to the PLINQ query as shown in the following code snippet:</p> <codesnippet> <font color="Blue">int</font>[]»numList»=»<font color="Blue">new»int</font>[25];</codesnippet> <codesnippet> </codesnippet> <codesnippet>»»»»»»»<font color="Blue">for»</font>(<font color="Blue">int»</font>i»=»1;»i»<=»numList.Count();»i++)</codesnippet> <codesnippet>»»»»»»»{</codesnippet> <codesnippet>»»»»»»»»»»»numList[i»-»1]»=»i;</codesnippet> <codesnippet>»»»»»»»}</codesnippet> <codesnippet> </codesnippet> <codesnippet>»»»»»»»<font color="Blue">int</font>[]»resultSet»=»(<font color="Blue">from»</font>x»<font color="Blue">in</font></codesnippet> <codesnippet>»»»»»»»»»»»»»»»»»»»»»»»»»numList.AsParallel(</codesnippet> <codesnippet>»»»»»»»»»»»»»»»»»»»»»»»»»QueryOptions.PreserveOrdering)</codesnippet> <codesnippet>»»»»»»»»»»»»»»»»»»»»»»»»»<font color="Blue">select»</font>x»*»x).ToArray();</codesnippet> <codesnippet> </codesnippet> <codesnippet>»»»»»»»<font color="Blue">for»</font>(<font color="Blue">int»</font>index»=»0;»index»<»resultSet.Length;»</codesnippet> <codesnippet>»»»»»»»»»»»»index++)</codesnippet> <codesnippet>»»»»»»»{</codesnippet> <codesnippet>»»»»»»»»»»»Console.WriteLine(resultSet[index]);</codesnippet> <codesnippet>»»»»»»»}</codesnippet> <p id="36">When you pass QueryOptions.PreserveOrdering as a parameter to the AsParallel() method, the ordering of the resultant data is preserved. However, preserving the order is costly in terms of performance as it leads to an overhead for PLINQ to sort the data before it returns it.</p> <h2>Merge Options</h2> <p id="37">PLINQ partitions the input query to multiple partitions with each partition working on different parts of data on separate threads. You can use the WithMergeOptions<TSource> method to tell PLINQ the merge option you would like to opt for. Here’s an example:</p> <codesnippet> <font color="Blue">var»</font>result»=»<font color="Blue">from»</font>p»<font color="Blue">in</font></codesnippet> <codesnippet>»»»»primeNumbers.AsParallel().AsOrdered()</codesnippet> <codesnippet>»»»».WithMergeOptions(ParallelMergeOptions.NotBuffered)</codesnippet> <codesnippet>»»»<font color="Blue">where»</font>IsPrime(p)</codesnippet> <codesnippet>»»»<font color="Blue">select»</font>p;</codesnippet> <p id="38">The ParallelMergeOptions enumeration can have one of the three possible values:</p> <list type="bulleted"> <bulletedlist>Not Buffered</bulletedlist> <bulletedlist>Auto Buffered</bulletedlist> <bulletedlist>FullyBuffered</bulletedlist> </list> <h2>Handling Exceptions</h2> <p id="39">Exceptions are errors that occur at runtime. The PLINQ API provides support for handling exceptions that might occur while queries are being executed in parallel. You can handle such exceptions using the System.Threading.AggregateException class. To retrieve the exception details of the exception that has occurred, you can use the InnerException property of this class. </p> <p id="40">Here’s an example that illustrates this:</p> <codesnippet> <font color="Blue">try</font> </codesnippet> <codesnippet>»»»»»»»{</codesnippet> <codesnippet>»»»»»»»»»»»ProcessData(somedata);</codesnippet> <codesnippet>»»»»»»»}</codesnippet> <codesnippet> </codesnippet> <codesnippet>»»»»»»»<font color="Blue">catch»</font>(AggregateException»exceptionInstance)</codesnippet> <codesnippet>»»»»»»»{</codesnippet> <codesnippet>»»»»»»»»»»»Console.WriteLine(exceptionInstance.</codesnippet> <codesnippet>»»»»»»»»»»»»»»»»»»»»»»»»»»»»»InnerException.Message);</codesnippet> <codesnippet>»»»»»»»}</codesnippet> <h2>Summary</h2> <p id="41">Multi-core processors have now become a part and parcel of today’s computers. Parallel LINQ (PLINQ) is a part of Parallel FX extensions for Microsoft .NET that helps you to leverage the multiple cores in today’s systems without having to change much of your LINQ queries or even having to bother how it would work behind the scenes. Parallel LINQ (PLINQ) provides a programming model that enables LINQ developers to take advantage of parallel hardware to build applications that are high performant and those that can scale. </p> <p id="42">In this article we have had a discussion on the concepts of concurrency and parallelism and how PLINQ can be used to parallelize queries and take advantage of today’s computer systems to build applications that are high performant and have the ability to scale.</p> </body> <sidebars> <sidebar title="What Should You Multithread and Parallelize?"> <p id="43">Now, the million dollar question that arises is, what should you multithread? Should you multithread and parallelize any query? No. Note that any thread would be either CPU intensive, or I/O intensive, or a mix of both.</p> <p id="44">Now, I/O bound threads are necessarily sequential. Hence, you should parallelize such threads. Rather, potential good candidates for multithreading and PLINQ are threads that are CPU intensive and those that need to execute complex computational logic.</p> </sidebar> <sidebar title="Points to Ponder"> <p id="45">Parallelism, though it yields better performance and scalability, is not a good choice in all scenarios. Not all queries should be parallelized. Things are particularly complex when there are interdependencies. There may be a scenario where one particular task is dependent on the outcome or result of another task that precedes it resulting in a block in the current task’s execution. In such a case, it is very difficult to parallelize your tasks. However, if used judiciously, parallelism can definitely give a boost to your application’s performance and scalability.</p> </sidebar> <sidebar title="Suggested Reading"> <p id="46">Here are a few links to references for further study on this topic:</p> <p id="47">PLINQ documentation on MSDN </p> <p id="48">http://msdn.microsoft.com/en-us/library/dd460688%28VS.100%29.aspx </p> <p id="49">Parallel Computing Center on MSDN </p> <p id="50">http://msdn.microsoft.com/en-us/concurrency/default.aspx </p> <p id="51">http://code.msdn.microsoft.com/plinq</p> <p id="52">http://blogs.msdn.com/b/pfxteam/</p> <p id="53">Daniel Moth’s blog </p> <p id="54">http://www.danielmoth.com/Blog/index.htm </p> </sidebar> </sidebars> <figures> <figure id="1" src="UNKNOWNIMAGE"> <b>Figure 1: </b>Illustrating that a parallel query runs faster.</figure> </figures> <tables> </tables> <codelistings> <codelisting id="0" header="Listing 1: Program to display prime numbers"> <code> <font color="Blue">using»</font>System;</code> <code> <font color="Blue">using»</font>System.Threading.Tasks;</code> <code> <font color="Blue">using»</font>System.Collections;</code> <code> </code> <code> <font color="Blue">namespace»</font>PLINQ</code> <code>{</code> <code>»»»»<font color="Blue">class»</font>Program</code> <code>»»»»{</code> <code>»»»»»»»»<font color="Blue">static»void»</font>Main(<font color="Blue">string</font>[]»args)</code> <code>»»»»»»»»{</code> <code>»»»»»»»»»»»»ArrayList»primeNumbers»=»<font color="Blue">new»</font>ArrayList();</code> <code> </code> <code>»»»»»»»»»»»»<font color="Blue">for»</font>(<font color="Blue">int»</font>i»=»0;»i»<»999;»i++)</code> <code>»»»»»»»»»»»»{</code> <code>»»»»»»»»»»»»»»»»<font color="Blue">if»</font>(IsPrime(i))</code> <code>»»»»»»»»»»»»»»»»»»»»primeNumbers.Add(i);</code> <code>»»»»»»»»»»»»}</code> <code> </code> <code>»»»»»»»»»»»»<font color="Blue">for»</font>(<font color="Blue">int»</font>index»=»0;»index»<»primeNumbers.Count;»index++)</code> <code>»»»»»»»»»»»»{</code> <code>»»»»»»»»»»»»»»»»Console.WriteLine(primeNumbers[index]);</code> <code>»»»»»»»»»»»»}</code> <code> </code> <code>»»»»»»»»»»»»Console.Read();</code> <code>»»»»»»»»}</code> <code> </code> <code>»»»»»»»»<font color="Blue">private»static»bool»</font>IsPrime(<font color="Blue">int»</font>number)</code> <code>»»»»»»»»{</code> <code>»»»»»»»»»»»»<font color="Blue">if»</font>(number»<»2)</code> <code>»»»»»»»»»»»»»»»»<font color="Blue">return»false</font>;</code> <code> </code> <code>»»»»»»»»»»»»<font color="Blue">int»</font>limit»=»(<font color="Blue">int</font>)Math.Sqrt(number);</code> <code> </code> <code>»»»»»»»»»»»»<font color="Blue">for»</font>(<font color="Blue">int»</font>i»=»2;»i»<=»limit;»i++)</code> <code>»»»»»»»»»»»»»»»»<font color="Blue">if»</font>(number»%»i»==»0)</code> <code>»»»»»»»»»»»»»»»»»»»»<font color="Blue">return»false</font>;</code> <code>»»»»»»»»»»»»<font color="Blue">return»true</font>;</code> <code>»»»»»»»»}</code> <code>»»»»}</code> <code>}</code> <code> </code> </codelisting> <codelisting id="41" header="Listing 2: Using Parallel.For() to parallelize the query"> <code> <font color="Blue">using»</font>System;</code> <code> <font color="Blue">using»</font>System.Threading.Tasks;</code> <code> <font color="Blue">using»</font>System.Collections;</code> <code> </code> <code> <font color="Blue">namespace»</font>PLINQ</code> <code>{</code> <code>»»»»<font color="Blue">class»</font>Program</code> <code>»»»»{</code> <code>»»»»»»»»<font color="Blue">static»void»</font>Main(<font color="Blue">string</font>[]»args)</code> <code>»»»»»»»»{</code> <code>»»»»»»»»»»»»ArrayList»primeNumbers»=»<font color="Blue">new»</font>ArrayList();</code> <code> </code> <code>»»»»»»»»»»»»Parallel.For(0,»999,»i»=></code> <code>»»»»»»»»»»»»{</code> <code>»»»»»»»»»»»»»»»»<font color="Blue">if»</font>(IsPrime(i))</code> <code>»»»»»»»»»»»»»»»»»»»»primeNumbers.Add(i);</code> <code>»»»»»»»»»»»»});</code> <code> </code> <code>»»»»»»»»»»»»<font color="Blue">for»</font>(<font color="Blue">int»</font>index»=»0;»index»<»primeNumbers.Count;»index++)</code> <code>»»»»»»»»»»»»{</code> <code>»»»»»»»»»»»»»»»»Console.WriteLine(primeNumbers[index]);</code> <code>»»»»»»»»»»»»}</code> <code> </code> <code>»»»»»»»»»»»»Console.Read();</code> <code>»»»»»»»»}</code> <code> </code> <code>»»»»»»»»<font color="Blue">private»static»bool»</font>IsPrime(<font color="Blue">int»</font>number)</code> <code>»»»»»»»»{</code> <code>»»»»»»»»»»»»<font color="Blue">if»</font>(number»<»2)</code> <code>»»»»»»»»»»»»»»»»<font color="Blue">return»false</font>;</code> <code> </code> <code>»»»»»»»»»»»»<font color="Blue">int»</font>limit»=»(<font color="Blue">int</font>)Math.Sqrt(number);</code> <code> </code> <code>»»»»»»»»»»»»<font color="Blue">for»</font>(<font color="Blue">int»</font>i»=»2;»i»<=»limit;»i++)</code> <code>»»»»»»»»»»»»»»»»<font color="Blue">if»</font>(number»%»i»==»0)</code> <code>»»»»»»»»»»»»»»»»»»»»<font color="Blue">return»false</font>;</code> <code>»»»»»»»»»»»»<font color="Blue">return»true</font>;</code> <code>»»»»»»»»}</code> <code>»»»»}</code> <code>}</code> </codelisting> <codelisting id="81" header="Listing 3: Using PLINQ to display prime numbers"> <code> <font color="Blue">using»</font>System;</code> <code> <font color="Blue">using»</font>System.Linq;</code> <code> <font color="Blue">using»</font>System.Threading.Tasks;</code> <code> <font color="Blue">using»</font>System.Collections;</code> <code> </code> <code> <font color="Blue">namespace»</font>PLINQ</code> <code>{</code> <code>»»»»<font color="Blue">class»</font>Program</code> <code>»»»»{</code> <code>»»»»»»»»<font color="Blue">static»void»</font>Main(<font color="Blue">string</font>[]»args)</code> <code>»»»»»»»»{</code> <code>»»»»»»»»»»»»<font color="Blue">int</font>[]»primeNumbers»=»<font color="Blue">new»int</font>[1000];</code> <code> </code> <code>»»»»»»»»»»»»<font color="Blue">for»</font>(<font color="Blue">int»</font>i»=»2;»i»<»primeNumbers.Length;»i++)</code> <code>»»»»»»»»»»»»»»»»primeNumbers[i»-»2]»=»i;</code> <code> </code> <code>»»»»»»»»»»»»<font color="Blue">var»</font>result»=»<font color="Blue">from»</font>p»<font color="Blue">in»</font></code> <code>primeNumbers.AsParallel().AsOrdered()</code> <code> </code> <code> <font color="Blue">where»</font>IsPrime(p)»<font color="Blue">select»</font>p;</code> <code> </code> <code>»»»»»»»»»»»»<font color="Blue">foreach»</font>(<font color="Blue">var»</font>v»<font color="Blue">in»</font>result)</code> <code>»»»»»»»»»»»»{</code> <code>»»»»»»»»»»»»»»»»Console.WriteLine(v);</code> <code>»»»»»»»»»»»»}</code> <code> </code> <code>»»»»»»»»»»»»Console.Read();</code> <code>»»»»»»»»}</code> <code> </code> <code>»»»»»»»»<font color="Blue">private»static»bool»</font>IsPrime(<font color="Blue">int»</font>number)</code> <code>»»»»»»»»{</code> <code>»»»»»»»»»»»»<font color="Blue">if»</font>(number»<»2)</code> <code>»»»»»»»»»»»»»»»»<font color="Blue">return»false</font>;</code> <code> </code> <code>»»»»»»»»»»»»<font color="Blue">int»</font>limit»=»(<font color="Blue">int</font>)Math.Sqrt(number);</code> <code> </code> <code>»»»»»»»»»»»»<font color="Blue">for»</font>(<font color="Blue">int»</font>i»=»2;»i»<=»limit;»i++)</code> <code>»»»»»»»»»»»»»»»»<font color="Blue">if»</font>(number»%»i»==»0)</code> <code>»»»»»»»»»»»»»»»»»»»»<font color="Blue">return»false</font>;</code> <code>»»»»»»»»»»»»<font color="Blue">return»true</font>;</code> <code>»»»»»»»»}</code> <code>»»»»}</code> <code>}</code> </codelisting> <codelisting id="124" header="Listing 4: Retrieving the time elasped in executing the PLINQ query"> <code> <font color="Blue">using»</font>System;</code> <code> <font color="Blue">using»</font>System.Linq;</code> <code> <font color="Blue">using»</font>System.Threading.Tasks;</code> <code> <font color="Blue">using»</font>System.Collections;</code> <code> <font color="Blue">using»</font>System.Diagnostics;</code> <code> </code> <code> <font color="Blue">namespace»</font>PLINQ</code> <code>{</code> <code>»»»»<font color="Blue">class»</font>Program</code> <code>»»»»{</code> <code>»»»»»»»»<font color="Blue">static»void»</font>Main(<font color="Blue">string</font>[]»args)</code> <code>»»»»»»»»{</code> <code>»»»»»»»»»»»»<font color="Blue">int</font>[]»primeNumbers»=»<font color="Blue">new»int</font>[1000];</code> <code> </code> <code>»»»»»»»»»»»»<font color="Blue">for»</font>(<font color="Blue">int»</font>i»=»2;»i»<»primeNumbers.Length;»i++)</code> <code>»»»»»»»»»»»»»»»»primeNumbers[i»-»2]»=»i;</code> <code> </code> <code>»»»»»»»»»»»»Stopwatch»stopWatch»=»<font color="Blue">new»</font>Stopwatch();</code> <code>»»»»»»»»»»»»stopWatch.Start();</code> <code> </code> <code>»»»»»»»»»»»»<font color="Blue">var»</font>result»=»<font color="Blue">from»</font>p»<font color="Blue">in»</font>primeNumbers.AsParallel()</code> <code>»»»»»»»»»»»»»»»»»»»»»»»»»<font color="Blue">where»</font>IsPrime(p)</code> <code>»»»»»»»»»»»»»»»»»»»»»»»»»<font color="Blue">select»</font>p;</code> <code> </code> <code>»»»»»»»»»»»»<font color="Blue">foreach»</font>(<font color="Blue">var»</font>v»<font color="Blue">in»</font>result)</code> <code>»»»»»»»»»»»»{</code> <code>»»»»»»»»»»»»»»»»Console.WriteLine(v);</code> <code>»»»»»»»»»»»»}</code> <code> </code> <code>»»»»»»»»»»»»stopWatch.Stop();</code> <code>»»»»»»»»»»»»Console.WriteLine("Time»elapsed:»{0}",</code> <code>»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»stopWatch.Elapsed);</code> <code>»»»»»»»»»»»»Console.Read();</code> <code>»»»»»»»»}</code> <code> </code> <code>»»»»»»»»<font color="Blue">private»static»bool»</font>IsPrime(<font color="Blue">int»</font>number)</code> <code>»»»»»»»»{</code> <code>»»»»»»»»»»»»<font color="Blue">if»</font>(number»<»2)</code> <code>»»»»»»»»»»»»»»»»<font color="Blue">return»false</font>;</code> <code> </code> <code>»»»»»»»»»»»»<font color="Blue">int»</font>limit»=»(<font color="Blue">int</font>)Math.Sqrt(number);</code> <code> </code> <code>»»»»»»»»»»»»<font color="Blue">for»</font>(<font color="Blue">int»</font>i»=»2;»i»<=»limit;»i++)</code> <code>»»»»»»»»»»»»»»»»<font color="Blue">if»</font>(number»%»i»==»0)</code> <code>»»»»»»»»»»»»»»»»»»»»<font color="Blue">return»false</font>;</code> <code>»»»»»»»»»»»»<font color="Blue">return»true</font>;</code> <code>»»»»»»»»}</code> <code>»»»»}</code> <code>}</code> </codelisting> <codelisting id="173" header="Listing 5: Checking the difference in time for executing a query concurrently and in parallell"> <code> <font color="Blue">using»</font>System;</code> <code> <font color="Blue">using»</font>System.Linq;</code> <code> <font color="Blue">using»</font>System.Diagnostics;</code> <code> </code> <code> <font color="Blue">namespace»</font>PLINQ</code> <code>{</code> <code>»»»»<font color="Blue">class»</font>Program</code> <code>»»»»{</code> <code>»»»»»»»»<font color="Blue">static»void»</font>Main(<font color="Blue">string</font>[]»args)</code> <code>»»»»»»»»{</code> <code>»»»»»»»»»»»»<font color="Blue">for»</font>(<font color="Blue">int»</font>index»=»0;»index»<»5;»index++)</code> <code>»»»»»»»»»»»»{</code> <code>»»»»»»»»»»»»»»»»Console.WriteLine("Concurrent»Execution:»"»+»</code> <code>»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»GetTimeElasped(<font color="Blue">delegate</font></code> <code>»»»»»»»»»»»»»»»»{</code> <code>»»»»»»»»»»»»»»»»»»»»<font color="Blue">var»</font>dictionary»=»(<font color="Blue">from»</font>i»<font color="Blue">in»</font>Enumerable.Range(0,</code> <code>»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»999999)»<font color="Blue">where»</font>IsPrime(i)»</code> <code>»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»<font color="Blue">select»</font>i).ToDictionary(i»=>»i);</code> <code>»»»»»»»»»»»»»»»»}));</code> <code> </code> <code>»»»»»»»»»»»»»»»»Console.WriteLine("Parallel»Execution:»"»+»</code> <code>»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»GetTimeElasped(<font color="Blue">delegate</font></code> <code>»»»»»»»»»»»»»»»»{</code> <code>»»»»»»»»»»»»»»»»»»»»<font color="Blue">var»</font>dict»=»(<font color="Blue">from»</font>i»<font color="Blue">in»</font>Enumerable.Range(0,</code> <code>»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»999999).AsParallel()»</code> <code>»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»<font color="Blue">where»</font>IsPrime(i)»</code> <code>»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»<font color="Blue">select»</font>i).ToDictionary(i»=>»i);</code> <code>»»»»»»»»»»»»»»»»}));</code> <code>»»»»»»»»»»»»}</code> <code> </code> <code>»»»»»»»»»»»»Console.Read();</code> <code>»»»»»»»»}</code> <code> </code> <code>»»»»»»»»<font color="Blue">private»static»bool»</font>IsPrime(<font color="Blue">int»</font>number)</code> <code>»»»»»»»»{</code> <code>»»»»»»»»»»»»<font color="Blue">if»</font>(number»<»2)</code> <code>»»»»»»»»»»»»»»»»<font color="Blue">return»false</font>;</code> <code> </code> <code>»»»»»»»»»»»»<font color="Blue">int»</font>limit»=»(<font color="Blue">int</font>)Math.Sqrt(number);</code> <code> </code> <code>»»»»»»»»»»»»<font color="Blue">for»</font>(<font color="Blue">int»</font>i»=»2;»i»<=»limit;»i++)</code> <code>»»»»»»»»»»»»»»»»<font color="Blue">if»</font>(number»%»i»==»0)</code> <code>»»»»»»»»»»»»»»»»»»»»<font color="Blue">return»false</font>;</code> <code>»»»»»»»»»»»»<font color="Blue">return»true</font>;</code> <code>»»»»»»»»}</code> <code> </code> <code>»»»»»»»»<font color="Blue">private»static»</font>TimeSpan»GetTimeElasped(Action»action)</code> <code>»»»»»»»»{</code> <code>»»»»»»»»»»»»Stopwatch»stopWatch»=»<font color="Blue">new»</font>Stopwatch();</code> <code>»»»»»»»»»»»»stopWatch.Start();</code> <code>»»»»»»»»»»»»action();</code> <code>»»»»»»»»»»»»<font color="Blue">return»</font>stopWatch.Elapsed;</code> <code>»»»»»»»»}</code> <code>»»»»}</code> <code>}</code> </codelisting> </codelistings> </document>