Да, скорее всего, вы переполняете пул потоков Mono, который снижает производительность вашей системы до минимума.
Если вы помните одну вещь из этого, то это то, что потоки дороги ,Каждый поток нуждается в своем собственном стеке (размер в мегабайтах) и частоте процессорного времени (требующий переключения контекста).Из-за этого редко бывает полезно раскрутить собственный поток для краткосрочных задач.Вот почему .NET имеет ThreadPool.
ThreadPool - это существующая коллекция потоков для коротких задач, и именно это пользователи F # для своих рабочих процессов Async.Всякий раз, когда вы выполняете асинхронную операцию F #, она просто делегирует действие пулу потоков.
Проблема в том, что происходит, когда вы одновременно запускаете тысячи асинхронных действий в F #?Наивная реализация просто порождает столько потоков, сколько необходимо.Однако, если вам нужно 1000 потоков, это означает, что вам нужно 1000 x 4 МБ стекового пространства.Даже если у вас достаточно памяти для всех стеков, ваш ЦП будет постоянно переключаться между различными потоками.(И подкачка локальных стеков в и из памяти.)
IIRC, реализация Windows .NET была достаточно умной, чтобы не создавать тонну потоков и просто ставить в очередь работу до тех пор, пока не появятся некоторые запасные потоки для выполнениядействия.Другими словами, он будет продолжать добавлять потоки, пока у него не будет фиксированного числа, и просто использовать их.Однако я не знаю, как реализован пул потоков Mono.
tl; dr: Это работает, как и ожидалось.