Для максимальной производительности при одновременном выполнении модулей напишите свой собственный пул потоков, в котором пул объектов потоков создается при запуске и переходит в режим блокировки (ранее приостановлен), ожидая запуска контекста (объект со стандартным интерфейсом, реализованный с помощью ваш код).
Так много статей о задачах, потоках и .NET ThreadPool не могут дать вам того, что вам нужно, чтобы принять решение о производительности. Но когда вы их сравниваете, выигрывают потоки и особенно пул потоков. Они лучше всего распределяются между процессорами и запускаются быстрее.
Следует обсудить тот факт, что основной исполнительной единицей Windows (включая Windows 10) является поток, и накладные расходы на переключение контекста ОС обычно незначительны. Проще говоря, мне не удалось найти убедительных доказательств многих из этих статей, независимо от того, утверждается ли в статье более высокая производительность за счет сохранения переключения контекста или лучшего использования ЦП.
Теперь немного реализма:
Большинству из нас не нужно, чтобы наше приложение было детерминированным, и у большинства из нас нет опыта работы с потоками, который, например, часто возникает при разработке операционной системы. То, что я написал выше, не для новичка.
Поэтому, возможно, наиболее важным является обсуждение того, что легко программировать.
Если вы создадите свой собственный пул потоков, вам придется немного написать, так как вам нужно будет заботиться об отслеживании статуса выполнения, как имитировать приостановку и возобновление и как отменить выполнение, в том числе в масштабе всего приложения. неисправность. Возможно, вам также придется позаботиться о том, хотите ли вы динамически наращивать свой пул, а также о том, какие ограничения емкости будет иметь ваш пул. Я могу написать такую структуру за час, но это потому, что я делал это много раз.
Возможно, самый простой способ написать исполнительную единицу - использовать Task. Прелесть Задачи в том, что вы можете создать ее и запустить ее прямо в коде (хотя может потребоваться осторожность). Вы можете передать токен отмены для обработки, когда хотите отменить задачу. Кроме того, он использует подход обещаний к цепочке событий, и вы можете заставить его возвращать определенный тип значения. Более того, с async и await существует больше возможностей, и ваш код будет более переносимым.
По сути, важно понимать плюсы и минусы задач, потоков и .NET ThreadPool. Если мне нужна высокая производительность, я буду использовать потоки и предпочитаю использовать свой собственный пул.
Легкий способ сравнения - запустить 512 потоков, 512 задач и 512 потоков ThreadPool. Вы обнаружите задержку в начале с потоками (отсюда и зачем писать пул потоков), но все 512 потоков будут запущены через несколько секунд, в то время как задачи и потоки .NET ThreadPool начнутся через несколько минут.
Ниже приведены результаты такого теста (четырехъядерный процессор i5 с 16 ГБ ОЗУ), дающий каждые 30 секунд на выполнение. Выполняемый код выполняет простой файловый ввод-вывод на SSD-диске.
Результаты теста