How .NET Parallel.Foreach construct with IO intensive operations

Viewed 518

Say, I write a program which is supposed to read all text files in a given and produce a list of objects of out of it.

So steps are

  1. Read File content From Disk for all files in the given folder.
  2. Create unique object per file content.

I'm questioning if Parallel.ForEach in .NET (or any other parallelism construct) will improve performance of step 1 and how. Aren't disk's IO are synchronous in nature i.e. The head of a disk can not be in 5 places at the same time. As a matter of fact it may make things slower?

What are your thoughts on this?

2 Answers

Let's distinguish two different concepts:

  • Concurrency: Doing more than one thing at a time.
  • Parallelism: Doing lots of work by dividing it up among multiple threads that run concurrently.

(These definitions are from Stephen Cleary's Concurrency in C# Cookbook.)

Concurrency does not require multiple executors. It could work with a single one and it can use context switching to make progress on each task. (At a given point in a time it suspends the execution of a given task and it switches to another job.)

On the other hand when we talk about parallel processing then we can assume that there are multiple available executors and that's why multiple jobs can make progress at the same time.

Concurrent vs Parallel
Source


In case .NET when we talk about Parallel Programming most of the time we refer to CPU bound operations. That's why Parallel.Foreach, Parallel.For and Parallel.Invoke are designed for multi-threading.

If you visit the related MSDN article then it would be misleading at the first sight. It uses an example which reads files from a given folder. But please pay attention to this comment:

Parallel.ForEach(files, (currentFile) =>
{
    // The more computational work you do here, the greater the speedup compared to a sequential foreach loop.

So, depending on the work what you want to do, Parallel.XYZ or PLinq may not be the best choice. If you want to execute multiple async I/O operations concurrently then Task.WhenAll is your best friend.


If you want to better understand parallel programming then I would suggest to read Stephen Toub's excellent whitepaper: Patterns of Parallel Programming C#

I would also encourage you watch Jeffry Richter's presentations about async I/O and scalable applications.

Firstly, SSDs are ubiquitous nowadays and are not affected anywhere near as much by random reads as were the old HDDs. A RAID setup (or a SAN) can also do big parallel operations.

But if you are fundamentally IO-bound i.e. you are waiting on the disk and not doing a lot of processing, then no, it does not make sense to go parallel. All that will happen is you will have more waiting threads, and as you say, also more random reads and less sequential.

It may make sense to have one thread just do I/O and another couple to do processing, this way the I/O queue depth remains deep because new requests are constantly coming through.


If your code is heavy on the CPU and is not limited as much by I/O, that is when you use full parallelism. For example de/compression, encryption and decryption.

Related