Если говорить о моем опыте работы с большими IRC-серверами, мы использовали select () и poll () (потому что epoll () / kqueue () не были доступны). При примерно 700 одновременных клиентах сервер будет использовать 100% ЦП (сервер irc не был многопоточным). Однако, что интересно, сервер все равно будет работать хорошо. При количестве клиентов около 4000 сервер начинает отставать.
Причиной этого было то, что около 700-ти клиентов, когда мы вернемся к select (), для обработки был доступен один клиент. Функция for () выполняет циклическое сканирование, чтобы выяснить, какой клиент потребляет большую часть процессора. По мере того, как у нас становилось больше клиентов, мы начинали получать все больше и больше клиентов, нуждающихся в обработке в каждом вызове select (), поэтому мы стали более эффективными.
Переходя к epoll () / kqueue (), аналогичные специализированные машины будут тривиально работать с 10 000 клиентов, а некоторые (по общему мнению, более мощные машины, но все же машины, которые по нынешним стандартам считаются крошечными), содержат 30 000 клиентов без пота.
Эксперименты, которые я видел с SIGIO, показывают, что он хорошо работает для приложений, где задержка чрезвычайно важна, когда только несколько активных клиентов выполняют очень мало индивидуальной работы.
Я бы рекомендовал использовать epoll () / kqueue () вместо select () / poll () практически в любой ситуации. Я не экспериментировал с разделением клиентов между потоками. Честно говоря, я никогда не находил сервис, который требовал бы дополнительной работы по оптимизации для обработки клиентского интерфейса, чтобы оправдать эксперименты с потоками.