Yes, most likely you are suppressing the Mono thread pool, which is stopping your system.
If you remember one thing from this, that flows streams . Each thread needs its own stack (megabytes in size) and a fragment of processor time (context switching is required). Because of this, it is rarely a good idea to deploy your own thread for short-lived tasks. This is why .NET has ThreadPool.
ThreadPool is an existing collection of threads for short tasks, and this is what F # users use Async for their workflows. Whenever you perform an F # Async operation, it simply delegates the action to the thread pool.
The problem is what happens when you immediately run thousands of asynchronous actions in F #? The naive implementation simply spawned as many threads as needed. However, if you need 1000 threads, that means you need 1000 x 4 MB of stack space. Even if you have enough memory for all the stacks, your processor will constantly switch between different threads. (And swapping local stacks to and from memory.)
IIRC, the implementation of Windows.NET, was smart enough not to create a ton of threads and just queue up for work until some spare threads were created to take action. In other words, it will continue to add threads until there is a fixed number, and just use them. However, I do not know how the Mono thread pool is implemented.
tl; dr: This works as expected.
source share