PLINQ is the parallelized version of LINQ to Objects and supports all existing LINQ operators and functionality with a few new options for fine-grained control of parallelization functionality.
At the time of writing, LINQ to SQL and LINQ to Entities will not benefit from parallelization because in these cases the query is executed on the database or the provider, so .NET cannot parallelize it.
Parallelizing LINQ queries automatically is potentially the ultimate goal for LINQ, but it can introduce some issues (particularly around ordering), so at present you have to opt in to the parallel model.
A WORD OF WARNINGWhen using PLINQ, it is important to ensure that your query does not modify the result set because this might have unforeseen effects if values are utilized later in the query. PLINQ will try to work out how best to process the query (including not running it in parallel at all), but do you really want to take the chance of weird, scary, and hard-to-reproduce bugs? |
This example iterates through all the objects in the stock list, calls an external service, and processes the result.
Writing such a query in traditional LINQ might look something like this:
var query = from s in Stocks let result = StockService.CallService(s) select result;
To run the same query in parallel, simply use the .AsParallel() extension method to the Stocks object:
var query = from s in Stocks.AsParallel() let result = StockService.CallService(s) select result;
It really is as easy as that (well, almost).
As items are processed in parallel you should not write code that is dependent on tasks being processed in a specific order. To order the results of your queries, use the AsOrdered() method to tell .NET to buffer the results before sorting them. This will slow the query down slightly because PLINQ now has to do additional work to preserve the ordering and merge the output:
var query = from s in Stocks.AsParallel().AsOrdered() orderby s.Company let company = s.Company let result = StockService.CallService(s)
Note that the AsUnordered() operator can be used to tell PLINQ that you no longer care about ordering items.
If, however, the order of your results is not important, you should use the ForAll() operator, which avoids merging the results set and executes more quickly:
query.ForAll(result => Console.WriteLine(result));
|
The AsSequential() method forces PLINQ to process all operations sequentially, which can sometimes be required when you are working with user-defined query methods:
var query = from s in Stocks.AsParallel().AsSequential() let result = StockService.CallService(s) select result;
The WithMergeOptions operator allows you to tell PLINQ how you want results to be merged when processing is complete. PLINQ is not guaranteed to do this, though. WithMergeOptions operates in three modes:
NotBuffered: Results are returned sooner, but more slowly overall.
FullyBuffered: This option is the quickest, but results are returned the most slowly.
AutoBuffered: This chunks returned items together, offering a middle ground between the other two options.
Sometimes the overhead of parallelizing a query can actually make it perform more slowly than if it were run sequentially, so be sure to measure your queries' performance. LINQ queries are not actually executed until you enumerate through them (deferred execution), so measuring performance can be slightly harder. Thus, if you want to measure the performance, be sure to iterate through the data in the result set or call a method such as ToList().
|
You can cancel a PLINQ query by passing in a CancellationTokenSource, which is discussed very shortly, into the WithCancellation()method.
When a query is run in parallel, exceptions can occur in multiple threads. PLINQ aggregates these exceptions into an AggregateException class and returns them back to the caller. You can then iterate through each individual exception.
If you run the following example, you need to modify a setting in the IDE to see it working. To do this, go to Tools Options Debugging General and uncheck the "Enable just my code option" or run in Release mode.
//select stock that doesnt exist var query = from s in Stocks.AsParallel() let result = StockService.CallService(Stocks[11]) select result; try { query.ForAll(result=>Console.WriteLine(result.ToString())); } catch (AggregateException e) { foreach (var ex in e.InnerExceptions) { Console.WriteLine(ex.Message); } }
3.149.24.98