Ответ 1
Класс Parallel
использует внутреннее средство TPL, которое называется самореплицирующими задачами. Они предназначены для использования всех доступных ресурсов потоков. Я не знаю, какие ограничения существуют, но кажется, что это всепоглощающее. Я ответил в основном тем же вопросом несколько дней назад.
Класс Parallel
подвержен возникновению безумных задач без ограничений. Легко спровоцировать его буквально порождать неограниченные потоки (2 в секунду). Я считаю класс Parallel
непригодным для использования без указанного вручную max-DOP. Это бомба замедленного действия, которая случайно взрывается в производстве под нагрузкой.
Parallel
особенно ядовит в сценариях ASP.NET, где многие запросы используют один пул потоков.
Обновление: Я забыл сделать ключевой момент. Таймеры тикера помещаются в очередь на пул потоков. Если пул насыщен, они попадают в линию и выполняются позднее. (Это причина, по которой таймеры могут происходить одновременно или после остановки таймеров.) Это объясняет, что вы видите. Способ исправить это, чтобы исправить перегрузку пула.
Лучшим решением для этого конкретного сценария будет настраиваемый планировщик задач с фиксированным количеством потоков. Parallel
можно использовать для использования планировщика задач. У Parallel Extension Extras есть такой планировщик. Получите эту работу из общего потока потоков. Как правило, я бы recomment PLINQ, но это не в состоянии принять планировщик. В некотором смысле, как Parallel, так и PLINQ являются бесполезно искалеченными API.
Не используйте ThreadPool.SetMinThreads
. Не связывайтесь с глобальными настройками процесса. Просто оставьте бедный пул нитей.
Кроме того, не используйте Environment.ProcessorCount -1
, потому что это отбрасывает одно ядро.
таймер уже выполнен в собственном потоке
Таймер - это структура данных в ядре ОС. Нет нити, пока галочка не будет поставлена в очередь. Не уверен, как именно это работает, но тик в конечном итоге помещается в пул потоков в .NET. Вот когда проблема начинается.
В качестве решения вы можете запустить поток, который спит в цикле, чтобы имитировать таймер. Это взлом, хотя, потому что он не устраняет основную причину: перегруженный пул потоков.