2

I wonder why in a specific case, there is a kind of "limitation" about the paralel process about async/await. For example this piece of code (running on .net core 3.1) :

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

public class Program
{
        async static Task Main(string[] args)
        {
            Console.WriteLine("Before - " + DateTime.Now.ToLongTimeString());
            var list = await (Task.WhenAll((await GetList()).Select(async l => new { Value = l, Text = await Wait(l) })));
            Console.WriteLine("After - " + DateTime.Now.ToLongTimeString());
            Console.WriteLine("Count - " + list.Count());

            Console.ReadLine();
        }

        async static Task<IEnumerable<int>> GetList()
        {
            IEnumerable<int> list = Enumerable.Range(1, 20);
            return await Task.FromResult(list);
        }

        async static Task<string> Wait(int index)
        {
            Console.WriteLine(index + " - During Before - " + DateTime.Now.ToLongTimeString());
            await Task.Run(() => {
                Thread.Sleep(5000);
            });
            Console.WriteLine(index + " - During After - " + DateTime.Now.ToLongTimeString());

            return "ok";
        }
}

So I expect to get my 20 elements of the array processing in the same time, and 5 second later, release all of them and finish the program.

Here the output:

Before - 12:11:05
1 - During Before - 12:11:05
2 - During Before - 12:11:05
3 - During Before - 12:11:05
4 - During Before - 12:11:05
5 - During Before - 12:11:05
6 - During Before - 12:11:05
7 - During Before - 12:11:05 
8 - During Before - 12:11:05 
9 - During Before - 12:11:05 
10 - During Before - 12:11:05
11 - During Before - 12:11:05
12 - During Before - 12:11:05
13 - During Before - 12:11:05
14 - During Before - 12:11:05
15 - During Before - 12:11:05
16 - During Before - 12:11:05
17 - During Before - 12:11:05
18 - During Before - 12:11:05
19 - During Before - 12:11:05
20 - During Before - 12:11:05
1 - During After - 12:11:10
2 - During After - 12:11:10
4 - During After - 12:11:10
3 - During After - 12:11:10
7 - During After - 12:11:10
8 - During After - 12:11:10
6 - During After - 12:11:10
5 - During After - 12:11:10
9 - During After - 12:11:11
10 - During After - 12:11:12
11 - During After - 12:11:13
12 - During After - 12:11:14
13 - During After - 12:11:15
14 - During After - 12:11:15
15 - During After - 12:11:15
16 - During After - 12:11:15
18 - During After - 12:11:15
17 - During After - 12:11:15
19 - During After - 12:11:15
20 - During After - 12:11:15
After - 12:11:15
Count - 20

It took 10s for running instead of 5s.

Everything is fine for the 20 "During before". As expected.
But for the next 20 "During After", from 9 to 13, each thread finishing every second.
So I guess there is something specific during this piece of code, but I don't understand what:

(await GetList()).Select(async l => new { Value = l, Text = await Wait(l) })

Is someone have some explanation please ?

Dams
  • 115
  • 6
  • 8
    I suspect you're just seeing the threadpool expansion policy. You're creating 20 threads just to sleep. Change your "sleep" part to just `await Task.Delay(5000);` and I suspect you'll see what you expect. – Jon Skeet Apr 29 '20 at 11:11
  • 1
    Try configuring the [`ThreadPool`](https://learn.microsoft.com/en-us/dotnet/api/system.threading.threadpool) with `ThreadPool.SetMinThreads(100, 10)` at the start of the program, to see if it makes any difference. – Theodor Zoulias Apr 29 '20 at 11:18
  • 1
    You're both right. By the `SetMinThreads` documentation, I better understand how the configuration of the limitation of the thread work. https://learn.microsoft.com/en-us/dotnet/api/system.threading.threadpool.setminthreads?view=netcore-3.1 Thanks a lot guys. :) – Dams Apr 29 '20 at 12:16
  • Is someone of you can create an answer please ? So I can mark it as accepted. :) – Dams Apr 29 '20 at 12:19
  • You should also read about the differences in [asynchronous programming and parallel programming](https://learn.microsoft.com/en-us/dotnet/standard/parallel-processing-and-concurrency), they are not the same thing – Liam Apr 29 '20 at 13:24
  • So I understand is mostly `Task.Run` causing the issue instead of async/await. I'll read your link. Thanks for your help :) – Dams Apr 29 '20 at 17:28

1 Answers1

-1

The ThreadPool is a workaround of the problem, and be able to launch the process with less limitation. But the thing still there.
But knowing this bring the answer to the problem:

In the code, the root of the problem is Task.Run, as is using the TreadPool for processing the delegate.
So directly use the internal method or replace Task.Run by something else resolve the original issue.

Dams
  • 115
  • 6