0

As I understood from the answers on the forum, it is better not to use asynchronous methods with Parallel.For/ForEach/Invoke. I noticed that there is no waiting on the main thread and the program just terminates.

Do I understand correctly that the Parallel.For/ForEach/Invoke methods do not wait on the main thread, how does it happen with synchronous methods and is it better not to use asynchronous methods with them?

Parallel.For. No waiting on the main thread

Random rnd = new Random();

async Task MyMethod()
{
    while (true)
    {
        Console.WriteLine(rnd.Next(1, 101));
        await Task.Delay(1000);
    }
}

Parallel.For(1, 5, (i) => MyMethod());

Parallel.ForEach. No waiting on the main thread

Random rnd = new Random();

async Task MyMethod()
{
    while (true)
    {
        Console.WriteLine(rnd.Next(1, 101));
        await Task.Delay(1000); 
    }
}

int[] MyArray = new int[5];

Parallel.ForEach(MyArray, (i) => MyMethod());

Parallel.Invoke. No waiting on the main thread

Random rnd = new Random();

async Task MyMethod()
{
    while (true)
    {
        Console.WriteLine(rnd.Next(1, 101));
        await Task.Delay(1000);
    }
}

Parallel.Invoke(() => MyMethod(), () => MyMethod(), () => MyMethod());

1 Answers1

0

Do I understand correctly that the Parallel.For/ForEach/Invoke methods do not wait on the main thread, how does it happen with synchronous methods and is it better not to use asynchronous methods with them?

All the Parallel.* methods block the current thread until all the work is completed.

In all of your examples the parallel method will simply run each asynchronous method until the first await is hit, since that is the end of the method as far as the Parallel method is concerned. You could do something like:

var results = new ConcurrentBag<Task>();
Parallel.ForEach(MyArray, (i) => results.Add(MyMethod()));
await Task.WhenAll(result);

This would start all the methods in a parallel way, and then await all created tasks. But doing this is mostly pointless.

Asynchronous code is mainly due to help with latency issues when calling some form of IO bound operation, or to save a bit of resources for server applications. Parallel.* on the other hand is mostly intended to speed up compute bound operations. The use cases do not really mix well in most cases.

If need to perform a list of asynchronous calls you can just as well use a regular loop:

var result = new List<Task>();
foreach(var item in MyArray){
    result.Add(MyMethod(item));
}
await Task.WhenAll(result);

This will likely be faster since you will avoid some of the overhead inherent in running anything in parallel.

When doing any kind of multi threaded programming you need to be concerned about thread safety. Random is not thread safe, so even this small toy example would not be thread safe. I would recommend reading a bit about thread safety before attempting any kind of multi threaded programming.

JonasH
  • 28,608
  • 2
  • 10
  • 23
  • _In all of your examples the parallel method will simply run each asynchronous method until the first await is hit, since that is the end of the method as far as the Parallel method is concerned_. Thank you! If I add at the bottom await Task.Delay(int.MaxValue); then the methods will work for a very long time. I correctly understand that Parallel.For waits in the main thread until it comes to await after that Parallel.For does not wait? That's all I need to know. –  Sep 03 '22 at 00:53