> This is an optional bonus section for Chapter 11. It is not required to complete the rest of the book.
- [Using multiple threads with parallel LINQ](#using-multiple-threads-with-parallel-linq)
- [Creating an app that benefits from multiple threads](#creating-an-app-that-benefits-from-multiple-threads)
- [Using Windows](#using-windows)
- [Using macOS](#using-macos)
- [For all operating systems](#for-all-operating-systems)
By default, only one thread is used to execute a LINQ query. Parallel LINQ (PLINQ) is an easy way to enable multiple threads to execute a LINQ query.
> **Good Practice**: Do not assume that using parallel threads will improve the performance of your applications. Always measure real-world timings and resource usage.
## Creating an app that benefits from multiple threads
To see it in action, we will start with some code that only uses a single thread to calculate Fibonacci numbers for 45 integers. We will use the `StopWatch` type to measure the change in performance.
We will use operating system tools to monitor the CPU and CPU core usage. If you do not have multiple CPUs or at least multiple cores, then this exercise won't show much!
1. Use your preferred code editor to add a new **Console App** / `console` project named `LinqInParallel` to the `Chapter11` solution/workspace.
- In Visual Studio Code, select `LinqInParallel` as the active OmniSharp project.
2. In `Program.cs`, delete the existing statements and then import the `System.Diagnostics` namespace so that we can use the `StopWatch` type. Add statements to create a stopwatch to record timings, wait for a keypress before starting the timer, create 45 integers, calculate the Fibonacci number for each of them, stop the timer, and display the elapsed milliseconds, as shown in the following code:
WriteLine($"Calculating Fibonacci sequence up to term {max}. Please wait...");
int[] fibonacciNumbers = numbers
.Select(number => Fibonacci(number))
.ToArray();
watch.Stop();
WriteLine("{0:#,##0} elapsed milliseconds.",
arg0: watch.ElapsedMilliseconds);
Write("Results:");
foreach (int number in fibonacciNumbers)
{
Write($" {number:N0}");
}
static int Fibonacci(int term) =>
term switch
{
1 => 0,
2 => 1,
_ => Fibonacci(term - 1) + Fibonacci(term - 2)
};
```
3. Run the console app, but do not press *Enter* to start the stopwatch yet because we need to make sure a monitoring tool is showing processor activity.
### Using Windows
If you are using Windows:
1. Right-click on the Windows Start button or press *Ctrl* + *Alt* + *Delete*, and then click on **Task Manager**.
2. At the bottom of the **Task Manager** window, click **More details**.
3. At the top of the **Task Manager** window, click on the **Performance** tab.
4. Right-click on the **CPU Utilization** graph, select **Change graph to**, and then select **Logical processors**.
### Using macOS
If you are using macOS:
1. Launch **Activity Monitor**.
2. Navigate to **View** | **Update Frequency Very often (1 sec)**.
3. To see the CPU graphs, navigate to **Window** | **CPU History**.
### For all operating systems
If you are using Windows or macOS or any other OS:
1. Rearrange your monitoring tool and your code editor so that they are side by side.
2. Wait for the CPUs to settle and then press *Enter* to start the stopwatch and run the query. The result should be a number of elapsed milliseconds, as shown in the following output:
```
Calculating Fibonacci sequence up to term 45. Please wait...
The monitoring tool will probably show that one or two CPUs were used the most, alternating over time. Others may execute background tasks at the same time, such as the garbage collector, so the other CPUs or cores won't be completely flat, but the work is certainly not being evenly spread among all the possible CPUs or cores. Also, note that some of the logical processors are maxing out at 100%.
3. In `Program.cs`, modify the query to make a call to the `AsParallel` extension method and to sort the resulting sequence, because when processing in parallel the results can become misordered, as shown highlighted in the following code:
```cs
int[] fibonacciNumbers = numbers.AsParallel()
.Select(number => Fibonacci(number))
.OrderBy(number => number)
.ToArray();
```
> **Good Practice**: Never call `AsParallel` at the end of a query. This does nothing. You must perform at least one operation after the call to `AsParallel` for that operation to be parallelized. .NET 6 introduced a code analyzer that will warn about this type of misuse.
4. Run the code, wait for CPU charts in your monitoring tool to settle, and then press *Enter* to start the stopwatch and run the query. This time, the application should complete in less time (although it might not be as less as you might hope for—managing those multiple threads takes extra effort!):
```
Calculating Fibonacci sequence up to term 45. Please wait...
5. The monitoring tool should show that all CPUs were used equally to execute the LINQ query and note that none of the logical processors max out at 100% because the work is more evenly spread.