опрос () в рубине? - PullRequest
       8

опрос () в рубине?

2 голосов
/ 07 апреля 2009

В настоящее время я портирую самописное сетевое приложение с C ++ на Ruby. Это сетевое приложение часто требует одновременного управления около 10.000 сокетов, а это значит, что ему нужен быстрый доступ ко всем сокетам с доступными для чтения данными, входящим соединениям и т. Д.

Я уже испытывал при написании этого на C ++, что select() не работает для этого случая, потому что внутренне он использует 32 DWORD s (128 байт) для управления максимально 1024 сокетами с битовыми масками. Так как мне иногда приходится работать с более чем 10.000 сокетов, этой функции не хватало. Поэтому мне пришлось переключиться на poll(), что также сделало код более элегантным, потому что у меня не всегда было добавление и удаление всех файловых дескрипторов снова.

Как я вижу из документации по Ruby, Ruby предлагает IO.select(), что, по сути, является оберткой для C-API (насколько я знаю). К сожалению, похоже, что нет IO.poll(), который мне понадобился бы для этого конкретного приложения.

Имеет ли IO.select() те же ограничения, что и select() в WinSocks и Berkeley Sockets? Если да, есть ли способ обойти это?

Ответы [ 3 ]

2 голосов
/ 06 февраля 2013

Выбор нельзя безопасно использовать с программами, которые имеют более 1024 файловых дескрипторов в системе Linux. Это связано с тем, что базовый набор fd_set, используемый системным вызовом select, представляет собой буфер фиксированного размера, т. Е. Его размер выделяется во время компиляции, а не во время выполнения.

От человека 2 выберите:

int select(int nfds, fd_set *readfds, fd_set *writefds,
           fd_set *exceptfds, struct timeval *timeout);

fd_set - это буфер фиксированного размера. Выполнение FD_CLR () или FD_SET () со значением fd, которое отрицательно или равно или больше чем FD_SETSIZE приведет к неопределенному поведению. Более того, POSIX требует, чтобы fd был допустимым дескриптором файла.

Это означает, что если в вашей программе более 1024 файловых дескрипторов, и вы используете системный вызов select, вы получите повреждение памяти.

Если вы хотите использовать в своей программе более 1024 дескрипторов файлов, вы должны использовать опрос или epoll и убедиться, что вы никогда не используете select, иначе вы получите случайное повреждение памяти. Изменение размера таблицы дескрипторов файлов с помощью ulimit очень опасно, если вы используете select. Не делай этого.

Кажется, что Ruby действительно реализован с помощью системного вызова select, так что, хотя может показаться, что увеличение ulimit работает, под капотом происходит повреждение: https://github.com/ruby/ruby/blob/trunk/thread.c

Кроме того, некоторые несвязанные API в ruby, похоже, используют select (см. Thread_pthread.c), поэтому, вероятно, также небезопасно использовать их или любой код, который использует эти API в программе ruby, работающей с таблицей дескрипторов файлов больше 1024.

1 голос
/ 08 апреля 2009

Ограничения на IO.select() и фактически количество открытых соединений, которые вы можете иметь на процесс, по-видимому, определяются главным образом поддержкой базовой операционной системы. Определенно нет фиксированного предела сокета 1024.

Например, под WinXP я открываю максимальное значение при открытии гнезда 69 (даже до того, как смогу выбрать). Я уверен, что это, вероятно, настраивается, я просто не знаю, как.

В Linux ограничение - это количество разрешенных открытых файлов. По умолчанию ограничение обычно составляет 1024 (запустите ulimit -a для проверки).

Однако вы можете легко изменить это, например. ulimit -n 10000. Я только что провел тест и успешно прошел 1024 активных сокета, созданных с помощью TCPSocket.new и использующих IO.select для проверки готовых данных.

Примечание: в этой статье GServer .

есть хороший пример использования IO.select.
0 голосов
/ 07 апреля 2009

IO :: Reactor может делать то, что вам нужно. У него есть метод опроса, который похож на то, что вы описываете.

...