С одним файловым дескриптором, есть ли разница в производительности между select, poll и epoll и …?

#c #sockets #select #epoll

#c #сокеты #выберите #epoll

Вопрос:

Название действительно говорит само за себя.

Средства и … также включают pselect и ppoll..

Серверный проект, над которым я работаю, в основном структурирован несколькими потоками. Каждый поток обрабатывает один или несколько сеансов. Все потоки идентичны. Протокол заботится о том, в каком потоке будет проходить сеанс.

Я использую внутренний класс сокета, который завершает работу. Интересным моментом является вызов checkread, который вызывает либо poll (Linux), либо select (Windows).

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

На страницах руководства для epoll есть краткое обсуждение запуска edge и level. Я не совсем уверен, что это значит. В классе socket я вижу оптимизацию в части кода Windows, которая сокращает вызов select с помощью ioctlsocket amp; FIONREAD, чтобы проверить, есть ли какие-либо данные. Интересно, вернет ли это значение > 0, даже если полный UDP-пакет не прибыл во время вызова. Это и есть запуск edge в epoll?

В некоторых элементарных тестированиях я также не вижу заметной разницы между использованием select и poll.

Я вижу, что использование ppoll может принести пользу, хотя из-за большей точности в таймауте. Есть мысли?

И да, я пытаюсь оптимизировать пропускную способность для сеанса, который получает много данных. Сервер больше привязан к сети и диску, чем к процессору.

Ответ №1:

Основное различие между epoll и select или poll заключается в том, что epoll масштабируется намного лучше при запуске в одном потоке. Я не знаю, как это можно сравнить с использованием многопоточного сервера с использованием select или poll. Посмотрите на это http://monkey.org /~provos/libevent/libevent-benchmark2.jpg

Причина этого (насколько я могу судить) заключается в том, что при использовании select или poll вы должны перебирать все подключенные сокеты, чтобы определить, в каких из них есть данные для чтения. Когда вы используете epoll, он сохраняет отдельный массив, который содержит ссылки только на сокеты, у которых есть данные для чтения. Это экономит вам множество циклов цикла, и разница становится все более заметной, чем больше подключено сокетов.

Еще одна вещь, на которую следует обратить внимание, если производительность когда-либо станет серьезной проблемой, — это порты завершения ввода-вывода (только для Windows) и kqueue (только для FreeBSD). Также важно помнить, что epoll — это только Linux. В большинстве случаев select или poll будут работать просто отлично.

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

Комментарии:

1. Спасибо, это в основном подтвердило то, что я нашел экспериментальным путем.

2. Вы не хотите использовать, select если один файловый дескриптор имеет большое число, поскольку select is O(max fd number) , тогда как poll is O(number of fds in the request) .

Ответ №2:

Согласно ссылке:http://www.intelliproject.net/articles/showArticle/index/io_multiplexing.

Если вы используете только один дескриптор:

  • select : 201 микросекунда.
  • poll : 159 микросекунд.
  • epoll : 176 микросекунд.

Кажется, poll это будет лучшим решением в такой ситуации.

Ответ №3:

Если у вас есть только один сокет, какой смысл опроса в первую очередь? Не будет ли лучшая производительность тогда при простом использовании блокировки чтения / записи?

Wrt. производительность, только с одним файловым дескриптором Я не думаю, что есть большая разница, если она вообще есть, между различными подходами. Если вас это действительно волнует, я полагаю, вы могли бы измерить, но мне трудно предположить, что это имело бы особое значение для общей производительности вашей программы.

Запуск уровня / границы. Предположим, что вы отслеживаете сигнал, для простоты скажем, некоторое напряжение в линии. Запуск Edge означает, что что-то срабатывает, когда напряжение превышает определенный предел. Запуск уровня означает, что что-то считается находящимся в запущенном состоянии, пока напряжение превышает / ниже предела. То есть, пограничный запуск срабатывает при возникновении некоторого события (пересечении некоторого порога), запуск уровня отражает состояние некоторой «вещи» (в данном случае напряжения).

Возвращаясь к сетевому программированию, система с пограничным запуском может быть такой, в которой вы получаете какой-то сигнал при получении пакета. Если вы не обрабатываете событие, то сигнал теряется. Система, запускаемая на уровне, OTOH, это что-то вроде запроса «есть ли данные, ожидающие меня в буфере?»; если вы не обработаете событие и не запросите снова, данные все еще будут там, ожидая вас.

Комментарии:

1. Используя poll, я могу использовать тайм-аут и выполнять другую работу в том же потоке. Я также могу использовать опрос для блокировки, когда больше нечего делать и когда я жду данных из сети. Я мог бы создать другой поток, но это создает другие проблемы с общими данными, среди прочего. Больше потоков = больше сложности и никакой пользы в моем случае. Перепробовал множество подходов.