Reader small image

You're reading from  Parallel Programming and Concurrency with C# 10 and .NET 6

Product typeBook
Published inAug 2022
PublisherPackt
ISBN-139781803243672
Edition1st Edition
Right arrow
Author (1)
Alvin Ashcraft
Alvin Ashcraft
author image
Alvin Ashcraft

Alvin Ashcraft is a software engineer and developer community champion with over 25 years of experience in software development. Working primarily with Microsoft Windows, web, and cloud technologies, his career has focused primarily on the healthcare industry. He has been awarded as a Microsoft MVP 11 times, most recently as a Windows Dev MVP. Alvin works in the Philadelphia area for Allscripts, a global healthcare software company, as a principal software engineer. He is also a board member of the TechBash Foundation, where he helps organize the annual TechBash developer conference. He has previously worked for companies such as Oracle, Genzeon, CSC, and ITG Pathfinders. Originally from the Allentown, PA area, Alvin currently resides in West Grove, PA with his wife and three daughters.
Read more about Alvin Ashcraft

Right arrow

Chapter 8: Parallel Data Structures and Parallel LINQ

.NET provides many useful features and data constructs for developers who are introducing parallelism to their projects. This chapter will explore these features, including concurrent collections, the SpinLock<T> synchronization primitive, and Parallel LINQ (PLINQ). These features can improve the performance of your applications while maintaining safe threading practices.

Most .NET developers are familiar with LINQ frameworks, including LINQ to Objects, LINQ to SQL, and LINQ to XML. There are even open source .NET LINQ libraries, such as LINQ to Twitter (https://github.com/JoeMayo/LinqToTwitter). We will take those LINQ skills and leverage them in parallel programming with PLINQ. Every LINQ developer can be a PLINQ developer after reading this chapter. Read ahead for some useful examples of working with PLINQ in C#.

In this chapter, you will learn about the following:

  • Introducing PLINQ
  • Converting LINQ queries...

Technical requirements

To follow along with the examples in this chapter, the following software is recommended for Windows developers:

  • Visual Studio 2022 version 17.0 or later.
  • .NET 6.
  • To complete the WPF sample, you will need to install the .NET desktop development workload for Visual Studio.

While these are recommended, if you have .NET 6 installed, you can use your preferred editor. For example, Visual Studio 2022 for Mac on macOS 10.13 or later, JetBrains Rider, or Visual Studio Code will work just as well.

All the code examples for this chapter can be found on GitHub at https://github.com/PacktPublishing/Parallel-Programming-and-Concurrency-with-C-sharp-10-and-.NET-6/tree/main/chapter08.

Let’s get started by discussing LINQ, PLINQ, and why the query language can be a great way to improve your parallel programming with C#.

Introducing PLINQ

PLINQ is a set of .NET extensions for LINQ that allow part of the LINQ query to execute in parallel by leveraging the thread pool. The PLINQ implementation provides parallel versions of all of the available LINQ query operations.

Like LINQ queries, PLINQ queries offer deferred execution. This means that the objects are not queried until they need to be enumerated. If you aren’t familiar with LINQ’s deferred execution, we will look at a simple example to illustrate the concept. Consider these two LINQ queries:

internal void QueryCities(List<string> cities)
{
    // Query is executed with ToList call
    List<string> citiesWithS = cities.Where(s => 
        s.StartsWith('S')).ToList();
    // Query is not executed here
    IEnumerable<string> citiesWithT = cities.Where(s => 
...

Converting LINQ queries to PLINQ

In this section, we will look at some additional PLINQ operators and show you how you can leverage them to turn existing LINQ queries into PLINQ queries. Your existing queries may have requirements for preserving the order of data. Perhaps your existing code doesn’t use LINQ at all. There could be an opportunity there to convert some logic in foreach loops into PLINQ operations.

The way to convert a LINQ query to a PLINQ query is by inserting an AsParallel() statement into the query, as we did in the previous section. Everything that follows AsParallel() will run in parallel until an AsSequential() statement is encountered.

If your queries require that the original order of objects be preserved, you can include an AsOrdered() statement:

var results = people.AsParallel().AsOrdered()
    .Where(p => p.LastName.StartsWith("H"));

However, this will not be as performant as queries that do not preserve...

Preserving data order and merging data with PLINQ

When fine-tuning PLINQ queries for your applications, there are some extension methods that impact the sequencing of data that you can leverage. Preserving the original order of your items may be something that is required. We have touched on the AsOrdered method in this chapter, and we will experiment with it in this section. When PLINQ operations have been completed and items are returned as part of the final enumeration, the data is merged from the segments that were created to operate on multiple threads. The merge behavior can be controlled by setting ParallelMergeOptions with the WithMergeOptions extension method. We will discuss the behavior of the three available merge options provided.

Let’s get started by creating some samples with the AsOrdered and AsUnordered extension methods.

PLINQ data order samples

In this section, we will create five methods that each accept the same set of data and perform the same...

Data structures for parallel programming in .NET

When working with parallel programming in .NET, and with PLINQ, you should take advantage of the data structures, types, and primitives that .NET provides. In this section, we will touch on concurrent collections and synchronization primitives.

Concurrent collections

Concurrent collections are useful when working with parallel programming. We will cover them in great detail in Chapter 9, but let’s quickly discuss how we can leverage them when working with PLINQ queries.

If you are simply selecting and sorting data with PLINQ, it is not necessary to incur the overhead that is added with the collections in the System.Collections.Concurrent namespace. However, if you are calling a method with ForAll that modifies items in your source data, you should use one of these current collections, such as BlockingCollection<T>, ConcurrentBag<T>, or ConcurrentDictionary<TKey, TValue>. They can also guard against any...

Summary

In this chapter, we learned about the power of PLINQ to introduce parallel processing to our LINQ queries. We started by looking at how PLINQ differs from standard LINQ queries. Next, we explored how to introduce PLINQ into existing code by converting some standard LINQ queries. It is important to understand how PLINQ is impacting the performance of your applications, and we examined some timings in our sample applications. (Later, in Chapter 10, we will discuss some tools to test your application performance while testing it locally.) We covered some optimizations you can make to your queries with merge options and data ordering. Finally, we wrapped up by touching on some other .NET data structures and types to help provide type safety and performance to your applications.

In the next chapter, we will explore each of the concurrent collections in the System.Collections.Concurrent namespace in depth. The concurrent collections are key to ensuring that your parallel and...

Questions

  1. Which PLINQ method signals that the query should start processing in parallel?
  2. Which PLINQ method signals that the query should not process in parallel any longer?
  3. Which method tells PLINQ to preserve the original order of the source data?
  4. Which PLINQ method will execute a delegate in parallel on each item in the query?
  5. What performance impact does AsOrdered() have on a PLINQ query?
  6. Which PLINQ operations cannot be used with ParallelMergeOptions.NotBuffered?
  7. Is PLINQ always faster than an equivalent LINQ query?
  8. Which PLINQ merge option would you select if you want results to stream back from the query as they become available?
lock icon
The rest of the chapter is locked
You have been reading a chapter from
Parallel Programming and Concurrency with C# 10 and .NET 6
Published in: Aug 2022Publisher: PacktISBN-13: 9781803243672
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
undefined
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at $15.99/month. Cancel anytime

Author (1)

author image
Alvin Ashcraft

Alvin Ashcraft is a software engineer and developer community champion with over 25 years of experience in software development. Working primarily with Microsoft Windows, web, and cloud technologies, his career has focused primarily on the healthcare industry. He has been awarded as a Microsoft MVP 11 times, most recently as a Windows Dev MVP. Alvin works in the Philadelphia area for Allscripts, a global healthcare software company, as a principal software engineer. He is also a board member of the TechBash Foundation, where he helps organize the annual TechBash developer conference. He has previously worked for companies such as Oracle, Genzeon, CSC, and ITG Pathfinders. Originally from the Allentown, PA area, Alvin currently resides in West Grove, PA with his wife and three daughters.
Read more about Alvin Ashcraft