12

Is there any reason to choose Parallel.ForEach instead of await ForEachAsync in any situation (or vice-versa)? or they are virtually the same?

await collection.ForEachAsync( m => { m.DoSomething(); } );

VS

Parallel.ForEach( collection, m => { m.DoSomething(); } );
RagnaRock
  • 2,432
  • 7
  • 34
  • 56

3 Answers3

6

They are not 'virtually the same' at all.

When you use functions from the Parallel class such as Parallel.ForEach() you are invoking some action, in which that action is broken up into multiple smaller actions, each carried out on different threads (aka multi-threaded).

ForEachAsync on the other hand is not necessarily multi-threaded. It is asynchronous and asynchronous operations are not multi-threaded ones (well they can be, but don't have to be, that depends on the implementation).

I strongly suggest reading the following post which goes into far more detail on the topic.

As for you question of

Is there any reason to choose Parallel.ForEach instead of await ForEachAsync in any situation

The answer is most definitely that there are reasons to do so, but in order to determine what kind of scenarios you would use one or the other, you have to understand them both.

Here's a simple example:

You have a collection of objects and you want to iterate over them and perform some kind of action. Do you care about the order in which those actions occur? If so do not use Parallel.ForEach() as there is no guarantee of the order in which they are invoked (due to its multi-threaded nature).

EDIT:

In your example, it all depends on how many items are in collection and how process-heavy DoSomething() is.

The reason for that is because Parallel.ForEach() is not free. There are trade-offs to be made. Setting up a multi-threaded environment takes time and if collection is small and/or DoSomething() doesn't take too long, then the time spent setting up those threads would be better (and usually faster) spent with a single-threaded async operation.

On the other hand, if collection is large and/or DoSomething() is a process-heavy task then Parallel.ForEach() will most definitely be the most performant option.

Darren Ruane
  • 2,385
  • 1
  • 8
  • 17
  • I've added an example. Can I assume then that performance wise there is no benefit in using the await async in that scenario? (since it doesn't create different threads to be run in parallel, the actual code is all done in one processor) – RagnaRock Mar 27 '19 at 17:23
  • Parallelism and multithreading are not the same thing at all. You can perform asynchronous operations in parallel without using multiple threads, for example. There are lots of ways of doing things in parallel. Using multiple threads is just one of them. – Servy Mar 27 '19 at 18:06
  • Yes. It's not what you said at all. You said, "When you use parallelism you are invoking some action [...] each carried out on different threads (aka multi-threaded)." which states that parallelism is multithreading, you say, "[...]do not use parallelism as there is no guarantee of the order in which they are invoked (due to its multi-threaded nature)" again, stating that parallelism is synonyms with multithreading. "Instead an asynchronous operation might be useful." Operations being asynchronous doesn't mean they're executed sequentially (they may or may not be, depending on the specifics). – Servy Mar 27 '19 at 18:15
  • "The reason for that is because parallelism is not free. There are trade-offs to be made. Setting up a multi-threaded environment takes time" Again, parallelism is not the same as multithreading. You can parallelize things without using multiple threads. – Servy Mar 27 '19 at 18:16
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/190782/discussion-between-darren-ruane-and-servy). – Darren Ruane Mar 27 '19 at 18:16
  • [This post](https://stackoverflow.com/a/23833635/1159478) explains not only the difference between asynchronous and multithreading, but also how "parallelism" relates to both of them, for any readers who were confused by this post. – Servy Mar 27 '19 at 18:20
5

it is all depend on the threads let's say you have the following class

public class person
    {
        public int ID { get; set; }
        public string Name { get; set; }
    }

and here is your main Class

List<person> persons = new List<person>()
            {
                new person{ ID = 1,Name="Ali"}
                ,new person{ ID = 2,Name="Gorge"}
                ,new person{ ID = 3,Name="Alex"}
                ,new person{ ID = 4,Name="Liz"}
                ,new person{ ID = 5,Name="Scott"}
                ,new person{ ID = 6,Name="Abby"}
                ,new person{ ID = 7,Name="Sarah"}
            };

            Parallel.ForEach(persons, (p) =>
            {
                Console.WriteLine($"Id : {p.ID} ,Name : {p.Name}");
            });

When you run this code the list items will be splits over diff threads and the code won't be running in order as you see in the following output I get the print in diff order than my original List enter image description here

and here I am running the same code one more time, but I get diff results

enter image description here

The reason for that because of the threads, the compiler divide to number of threads and every list run the items assigned to it the following pic show the diff threads

enter image description here

but when you run the following code

List<person> persons = new List<person>()
            {
                new person{ ID = 1,Name="Ali"}
                ,new person{ ID = 2,Name="Gorge"}
                ,new person{ ID = 3,Name="Alex"}
                ,new person{ ID = 4,Name="Liz"}
                ,new person{ ID = 5,Name="Scott"}
                ,new person{ ID = 6,Name="Abby"}
                ,new person{ ID = 7,Name="Sarah"}
            };

            await persons.ForEachAsync(async p => Console.WriteLine($"Id : {p.ID} ,Name : {p.Name}"));

you only get one thread as showing here

enter image description here

plus the data print will always be running in the same order of your list

I hope this answer explains the difference !

khaled Dehia
  • 821
  • 7
  • 13
1

Is there any reason to choose Parallel.ForEach instead of await ForEachAsync in any situation (or vice-versa)?

Parallel.ForEach is for synchronous code. Its delegate must be synchronous, and it is invoked synchronously.

ForEachAsync is not a standard algorithm. There are several different implementations, but generally they attempt to do a mixture of asynchrony and parallelism. They have to give up some of the self-balancing aspects of Parallel.ForEach. The vast majority of code does not need ForEachAsync; most code is either asynchronous or parallel.

Stephen Cleary
  • 437,863
  • 77
  • 675
  • 810