«Приемлемая задержка» полностью зависит от вашего приложения. Работа со всем в одном потоке действительно может помочь, если у вас очень строгие требования к задержке. К счастью, большинство приложений не предъявляют столь строгих требований.
Конечно, если только один поток может получать запросов, то связывание этого потока для вычисления ответа будет означать, что вы не сможете принимать другие запросы. В зависимости от того, что вы делаете, вы можете использовать асинхронный ввод-вывод (и т. Д.), Чтобы избежать модели «поток на запрос», но это значительно сложнее IMO и все равно заканчивается переключением контекста потока.
Иногда целесообразно ставить запросы в очередь, чтобы избежать обработки слишком большим количеством потоков: если ваша обработка связана с ЦП, нет смысла иметь сотни потоков - лучше иметь очередь задач производителя и потребителя и распределите их примерно по одному потоку на ядро. Это в основном то, что ThreadPoolExecutor
сделает, если вы, конечно, настроите его правильно. Это не сработает, если ваши запросы тратят много времени на ожидание внешних служб (включая диски, но в первую очередь другие сетевые службы) ... в этот момент вам нужно либо использовать модели асинхронного выполнения всякий раз, когда вы потенциально можете сделать ядро простаивает с блокирующим вызовом, или вы берете удар по переключению контекста потока и получаете множество потоков, полагаясь на планировщик потока, чтобы он работал достаточно хорошо.
Суть в том, что требования к задержке могут быть жесткими - по моему опыту, они значительно сложнее, чем требования к пропускной способности, поскольку их намного сложнее масштабировать. Это действительно зависит от контекста.