Here is a test method that starts (without awaiting) 100 Tasks that each call GetConsumingEnumerable
on a BlockingCollection
. (Update: the behavior described below is not specific to this method; it could be any synchronously blocking method call.) I would like to understand why after the first 10 tasks have started in parallel, the subsequent tasks start sequentially, each waiting almost exactly 1000 ms before the next task:
[TestMethod]
public void Test()
{
BlockingCollection<int> list = new();
Console.WriteLine(DateTime.UtcNow + @": " + "START");
for (int i = 0; i < 100; i++)
{
int x = i;
Task.Run(() =>
{
Console.WriteLine($"{DateTime.UtcNow}: Starting {x}");
// This will just block
foreach (int item in list.GetConsumingEnumerable())
{
Console.WriteLine($"{DateTime.UtcNow}: foo {x}");
}
// We'll never get here:
Console.WriteLine($"{DateTime.UtcNow}: Finishing {x}");
});
}
Console.WriteLine(DateTime.UtcNow + @": " + "END");
// Just to give the test enough time to print all messages
Thread.Sleep(100_000);
}
Here are the first 26 lines of the output:
02.02.2021 12:17:41: START
02.02.2021 12:17:41: END
02.02.2021 12:17:41: Starting 9
02.02.2021 12:17:41: Starting 0
02.02.2021 12:17:41: Starting 1
02.02.2021 12:17:41: Starting 6
02.02.2021 12:17:41: Starting 4
02.02.2021 12:17:41: Starting 2
02.02.2021 12:17:41: Starting 5
02.02.2021 12:17:41: Starting 7
02.02.2021 12:17:41: Starting 3
02.02.2021 12:17:41: Starting 8
02.02.2021 12:17:41: Starting 10
02.02.2021 12:17:42: Starting 11
02.02.2021 12:17:43: Starting 12
02.02.2021 12:17:44: Starting 13
02.02.2021 12:17:45: Starting 14
02.02.2021 12:17:45: Starting 15
02.02.2021 12:17:46: Starting 16
02.02.2021 12:17:47: Starting 17
02.02.2021 12:17:48: Starting 18
02.02.2021 12:17:49: Starting 19
02.02.2021 12:17:50: Starting 20
02.02.2021 12:17:51: Starting 21
02.02.2021 12:17:52: Starting 22
02.02.2021 12:17:53: Starting 23
02.02.2021 12:17:54: Starting 24
The first few lines are as expected. But why does it start waiting 1000 ms after task #10? My first assumption was that since GetConsumingEnumerable
blocks the thread, perhaps the threads in the thread pool are all used up after the 10th task, but that doesn't explain the 1000 ms delay.