Оговорки о выборе/опросе против реакторов epoll в Twisted

Все, что я прочитал и испытал (приложения, основанные на Tornado), приводит меня к мысли, что ePoll является естественной заменой для сетей с выбором и опросом, особенно с Twisted. Что делает меня параноидальным, его довольно редко для лучшей техники или методологии не приходить с ценой.

Чтение нескольких десятков сравнений между epoll и альтернативами показывает, что epoll явно является чемпионом скорости и масштабируемости, в частности, что он масштабируется линейным образом, что является фантастическим. Тем не менее, что касается процессора и использования памяти, является epoll все еще чемпионом?

Ответ 1

Для очень небольшого количества сокетов (конечно, зависит от вашего оборудования, но мы говорим о чем-то порядка 10 или менее), select может побить epoll в использовании памяти и скорости выполнения. Разумеется, для такого небольшого числа сокетов оба механизма настолько быстры, что на самом деле вы не заботитесь об этой разнице в подавляющем большинстве случаев.

Одно пояснение. Либо выборка, и шкала epoll линейно. Однако большая разница заключается в том, что API-интерфейсы, ориентированные на пользователя, имеют сложности, основанные на разных вещах. Стоимость вызова select грубо совпадает со значением наивысшего пронумерованного файлового дескриптора, который вы передаете. Если вы выберете один fd, 100, то это примерно вдвое дороже, чем выбор на одном fd, 50. Добавление большего количества fds ниже самого высокого уровня не является достаточно бесплатным, поэтому на практике это немного сложнее, но это является хорошим первым приближением для большинства реализаций.

Стоимость epoll ближе к числу файловых дескрипторов, которые на самом деле имеют на них события. Если вы контролируете 200 дескрипторов файлов, но только 100 из них имеют на них события, то вы (очень грубо) платите за эти 100 активных файловых дескрипторов. Именно здесь epoll предлагает одно из своих основных преимуществ перед выбором. Если у вас есть тысяча клиентов, которые в основном не работают, тогда, когда вы используете select, вы все равно платите за каждую тысячу из них. Тем не менее, с epoll, похоже, что у вас есть только несколько - вы платите только за те, которые активны в любой момент времени.

Все это означает, что epoll приведет к меньшему использованию ЦП для большинства рабочих нагрузок. Что касается использования памяти, это немного подбрасывает. select умеет представлять всю необходимую информацию очень компактным способом (один бит на дескриптор файла). И ограничение FD_SETSIZE (обычно 1024) на количество дескрипторов файлов, которое вы можете использовать с select, означает, что вы никогда не будете тратить больше 128 байт для каждого из трех наборов fd, которые вы можете использовать с select (чтение, запись, исключение). По сравнению с теми 384 байтами max, epoll - это своего рода свинья. Каждый файловый дескриптор представлен многобайтовой структурой. Однако, в абсолютном выражении, он все еще не собирается использовать много памяти. Вы можете представить огромное количество дескрипторов файлов в несколько десятков килобайт (примерно 20 тыс. На 1000 дескрипторов файлов, я думаю). И вы также можете указать, что вам нужно потратить все 384 этих байта с помощью select, если вы хотите отслеживать только один дескриптор файла, но его значение равно 1024, ведь с epoll вы потратили бы только 20 байтов. Тем не менее, все эти цифры довольно малы, поэтому это не имеет большого значения.

И еще одно преимущество epoll, которое, возможно, вы уже знаете, что он не ограничивается файловыми дескрипторами FD_SETSIZE. Вы можете использовать его для мониторинга как можно большего количества дескрипторов файлов. И если у вас есть только один файловый дескриптор, но его значение больше, чем FD_SETSIZE, epoll тоже работает с этим, но select не делает.

Случайно, я также недавно обнаружил один небольшой недостаток epoll по сравнению с select или poll. Хотя ни один из этих трех API-интерфейсов не поддерживает нормальные файлы (т.е. Файлы в файловой системе), select и poll представляют эту нехватку поддержки, поскольку сообщают о таких дескрипторах, как всегда читаемые и всегда записываемые. Это делает их непригодными для каких-либо значимых типов неблокирующих файловых систем ввода/вывода, программа, которая использует select или poll и, случается, сталкивается с файловым дескриптором из файловой системы, по крайней мере продолжит работу (или если она не удастся, это не будет из-за select или poll), хотя это, возможно, не с лучшей производительностью.

С другой стороны, epoll быстро завершится с ошибкой (EPERM, по-видимому), когда будет предложено контролировать такой файловый дескриптор. Строго говоря, это вряд ли неверно. Это просто указывает на отсутствие поддержки в явном виде. Обычно я приветствую явные условия сбоя, но это недокументировано (насколько я могу судить) и приводит к полностью сломанному приложению, а не к тому, которое просто работает с потенциально ухудшенной производительностью.

На практике единственное место, где я видел это, - это взаимодействие с stdio. Пользователь может перенаправить stdin или stdout из/в обычный файл. В то время как ранее stdin и stdout были бы трубой, поддерживаемой epoll просто отлично, тогда она становится обычным файлом, и epoll не удается громко, нарушая приложение.

Ответ 2

В тестах, проведенных в моей компании, возникла одна проблема с epoll(), поэтому единственная стоимость по сравнению с select.

При попытке чтения из сети с таймаутом создание epoll_fd (вместо FD_SET) и добавление fd в epoll_fd намного дороже, чем создание FD_SET (который является простым malloc).

Как и в предыдущем ответе, по мере того, как число FD в процессе становится большим, стоимость select() становится выше, но в нашем тестировании даже с значениями fd в 10 000 секунд выбор по-прежнему остается победителем. Это случаи, когда есть только один fd, на который ожидает поток, и просто пытается преодолеть тот факт, что чтение сети и запись в сети не таймаут при использовании модели блокирующего потока. Конечно, блокирующие модели потоков отличаются низкой производительностью по сравнению с неблокирующими реакторными системами, но бывают случаи, когда требуется интегрировать их с определенной базой кода.

Этот вид использования редко встречается в высокопроизводительных приложениях, потому что модели реактора не нужно создавать новый epoll_fd каждый раз. Для модели, где epoll_fd долговечен, что явно предпочтительнее для любого высокопроизводительного серверного дизайна --- epoll - это явный победитель во всех отношениях.