Multithreading with PLINQ
It's actually quite pleasing how simple it is to use multithreading with LINQ. After you have the Parallel LINQ extensions, call AsParallel on your enumerable collection.
Since the Parallel LINQ extensions are in beta, you need to take a few extra steps to prepare:
- You can find the Parallel LINQ extensions on Microsoft download pages, or use your favorite search engine to find the latest release.
- Install the Parallel LINQ extensions. By default, the December 2007 Community Tech Preview (CTP) installs here:
C:\Program Files\Microsoft Parallel Extensions Dec07 CTP
This folder contains a version of System.Threading.dll containing the LINQ parallel extensions.
- To access the extensions, you'll need to add a reference to the System.Threading.dll file contained in the Parallel LINQ folder. Use the Project > Add Reference option in Visual Studio and browse to the folder containing the downloaded System.Threading.dll in step 2.
Now you're ready.
To use Parallel LINQ, write your LINQ queries as before, include a from clause and select, whatever you need. (Although remember the caveat against ordering.) The from clause contains a range of variables, the keyword in, and the source containing the data to query. For example:
from num in numbers
This statement defines a range num, and the source collection is numbers. Add a call to AsParallel from the source collection numbers:
numbers.AsParallel()
The code in Listing 1 demonstrates the AsParallel method in context.
Listing 1 Using Parallel LINQ to sort a collection of integers.
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading; using System.Diagnostics; namespace PLinqDemo { class Program { static void Main(string[] args) { int[] largeArray = new int[10000]; Random rnd = new Random(DateTime.Now.Millisecond); for(int i=0; i<largeArray.Length; i++) { largeArray[i] = rnd.Next(10000); } Stopwatch watch = new Stopwatch(); watch.Start(); var results = from num in largeArray.AsParallel() where num % 2 == 0 select new { Number=num, ThreadID=Thread.CurrentThread.ManagedThreadId }; watch.Stop(); Console.WriteLine(watch.Elapsed.ToString()); Console.ReadLine(); } } }
At the time this article was written, PLINQ supported parallel queries over collections of objects and XML sources. (It is worth noting that on modern PCs 10,000 integers is not sufficiently complex to get performance gains; hence, the StopWatch may indicate that the code in Listing 1 actually runs faster without the call to AsParallel.)
AsParallel is overloaded and accepts variations on an integer argument and a ParallelQueryOptions enumeration. The integer argument is the degree of parallelism, or number of threads to use. The ParallelQueryOptions are None and PreserveOrdering. PreserveOrdering preserves the order of elements in the collection.