Все современные задачи делятся условно на 2 категории. CPU-bound. IO-bound.
Первые. Это рендеринг графики. Игры. Численные методы. Майнинг. И все такое. Под это делают разбиение задачи на Processes (Windows/Linux), Threads (Posix). Короче бьються на независимые части и запускаются на отдельных процессорах или ядрах или потоках железа. В таком случае загрузка железа максимальна и отдача максимальна. Биг-дата джобы сюда-же можно положить.
И второй тип задачи - это современные бизнес приложения которые большую часть времени (ну допустим 80%)
стоят на паузе и слушают сетевой порт. И как только что-то прилетает они начинают активничать. Практика показала что большую часть таких задач можно запускать в 1 потоке и все будет нормально. Главное чтоб обработчик долго не тупил. Отработал свой реактивный евент. Или там MQ событие или событие актора и перекинулся на следующее.
Вот. Если грамотно делать второй тип то на 10 потоках ОС можно запустить тысячи акторов или веб-хендлеров бизнес приложения и все будет норм. Тоесть мы фокусируемся на том что I/O важнее.
Попытка смешивать эти юзкейсы или менять местами приводила к проблемам. Например если запускать много потоков ОС в рамках одной бизнес задачи то они очень быстро зацепятся за какой-то глобальный объект (mutex, critical section) и большее число времени процессора будет тратиться не на бизнес задачу а обслуживание этой конкуренции. Вобщем конкарренси - это страшная беда. И парадоксально но увеличение числа ядер или процессоров даже не решают проблему конкарренси а усугубляют. Есть доклад по Erlang на эту тему. И вообще самое лучшее конкарренси - это когда его нет.
Есть еще статья Стоунбрейкера (создатель Postgresql) где он рассуждает на тему куда сгорают мегафлопы в современных dbms под нагрузкой и приходит к очень печальным выводам. Почитайте. Это тоже в тему CPU-bound.