#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
isO(max fd number)
, тогда какpoll
isO(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, я могу использовать тайм-аут и выполнять другую работу в том же потоке. Я также могу использовать опрос для блокировки, когда больше нечего делать и когда я жду данных из сети. Я мог бы создать другой поток, но это создает другие проблемы с общими данными, среди прочего. Больше потоков = больше сложности и никакой пользы в моем случае. Перепробовал множество подходов.