Эффективность между select () и recv с MSG_PEEK. Асинхронный - PullRequest
2 голосов
/ 08 сентября 2010

Хотелось бы узнать, что будет наиболее эффективно при проверке входящих данных (асинхронно).Допустим, у меня есть 500 соединений.У меня есть 3 сценария (которые я могу придумать):

  1. Использование select () для одновременной проверки сокетов FD_SETSIZE, а затем перебор всех из них для получения данных.(Разве для этого не потребуется два вызова recv для каждого возвращаемого сокета? MSG_PEEK для выделения буфера, а затем recv () его снова, который будет таким же, как # 3)время.(Разве это не будет похоже на # 3? Требуется два вызова recv.)
  2. Используйте recv () с MSG_PEEK по одному сокету за раз, выделите буфер, затем снова вызовите recv ().Разве это не было бы лучше, потому что мы можем пропустить все вызовы select ()?Или издержки одного вызова recv () слишком велики?

Я уже закодировал ситуации в 1 и 2, но я не уверен, какой использовать.Извините, если я немного неясен.

Спасибо

Ответы [ 3 ]

3 голосов
/ 08 сентября 2010

Вы можете просто выполнить некоторое моделирование эффективности в 3 сценариях, где:

Сценарий A (0/500 входящих данных)

  • для решения № 1, вы вызываете толькоодин select()
  • для решения № 2, вам нужно 500 select()
  • для решения № 3, вам нужно 500 recv()

Сценарий B (250/500 входящих данных)

  • для решения № 1, одиночное select() + (500 recv())
  • для решения № 2, 500 select() +(500 recv())
  • для решения № 3, 750 recv()

** предположим, что пропущен сокет без размера буфера @ нет входящих данных
ответ очевиден:)

3 голосов
/ 08 сентября 2010

FD_SETSIZE обычно 1024, поэтому вы можете проверить все 500 соединений одновременно. Затем вы будете выполнять два recv вызова только на те, которые готовы - скажем, для очень загруженной системы, например, полдюжины из них каждый раз. При других подходах вам понадобится еще около 500 системных вызовов (огромное количество «сбойных» вызовов recv или select, которые вы выполняете на сотнях сокетов, которые не будут готовы в любой момент времени! -.)

Кроме того, при подходе 1 вы можете заблокировать, пока хотя бы одно соединение не будет готово (в этом случае не будет служебной нагрузки, что не будет редкостью в системах, которые не слишком заняты) - с другими подходами вам нужно будет «опрашивать», то есть взбалтывать , непрерывно, сжигая огромные объемы ЦП ни к чему хорошему (или, если вы спите какое-то время после каждого цикла проверок, тогда у вас будет задержка ответа несмотря на то, что система вообще не занята - eep! -).

Именно поэтому я считаю опрос шаблоном анти : часто используется, но тем не менее разрушительный. Иногда у вас нет абсолютно никакой альтернативы (что в основном говорит о том, что вам приходится взаимодействовать с очень плохо спроектированными системами - увы, иногда в этой несовершенной жизни вы делаете должны! -), но когда любой порядочный альтернатива существует , но опрос все же очень плохая практика проектирования, и ее следует избегать.

1 голос
/ 08 сентября 2010

... наиболее эффективно при проверке входящих данных (асинхронно).Допустим, у меня есть 500 соединений.У меня есть 3 сценария (о которых я могу думать):

Использование select () для одновременной проверки сокетов FD_SETSIZE, а затем итерация по всем из них для получения данных.(Разве для этого не требуется два вызова recv для каждого возвращаемого сокета? MSG_PEEK, чтобы выделить буфер, а затем снова выполнить recv (), который будет таким же, как # 3)

Надеюсь, вы внимательносоздание вашего набора fd только с теми дескрипторами, которые в данный момент подключены ...?Затем вы перебираете набор и запускаете recv () только для тех, которые имеют условия чтения или исключения / ошибки (последнее различие между реализациями BSD и Windows).Хотя функционально это нормально (и, возможно, концептуально элегантно), в большинстве реальных приложений вам не нужно заглядывать перед извлечением: даже если вы не уверены в размере сообщения и знаете, что можете посмотреть его из буфера, выследует подумать, можете ли вы:

  • обработать сообщение порциями (например, прочитать любую хорошую единицу работы - может быть, 8k, обработать ее, а затем прочитать следующую <= 8k в тот же буфер ...)) </li>
  • чтение в буфер, который достаточно велик для большинства / всех сообщений, и динамически распределяет больше, только если вы обнаружите, что сообщение неполное

Использование select () для проверкиодна розетка за раз.(Разве это не будет похоже на # 3? Требуется два вызова recv.)

Не очень хорошо.Если вы останетесь однопоточным, вам нужно будет установить значение 0 для тайм-аута на select и крутиться как сумасшедший в дескрипторах listenig и client.Очень бесполезно расходует процессорное время и значительно снижает задержку.

Используйте recv () с MSG_PEEK по одному сокету за раз, выделите буфер, затем снова вызовите recv ().Разве это не было бы лучше, потому что мы можем пропустить все вызовы select ()?Или издержки одного вызова recv () слишком велики?

(не обращая внимания на то, что лучше избегать MSG_PEEK) - как узнать, на каком сокете находится MSG_PEEK или recv ()?Опять же, если вы однопоточны, то вы либо заблокируете при первой попытке peek / recv, либо используете неблокирующий режим, а затем безумно крутите все дескрипторы, надеясь, что peek / recv что-нибудь вернет.Расточительно.

Итак, придерживайтесь 1 или переходите к многопоточной модели.Для последнего самый простой подход для начала - это заставить цикл прослушивающего потока вызывать accept, и каждый раз, когда accept принимает новый клиентский дескриптор, он должен порождать новый поток для обработки соединения.Эти потоки обработки клиентских соединений могут просто блокироваться в recv ().Таким образом, операционная система сама выполняет мониторинг и активацию потоков в ответ на события, и вы можете быть уверены, что это будет достаточно эффективно.Хотя эта модель звучит просто, вы должны знать, что многопоточное программирование имеет много других сложностей - если вы еще не знакомы с ней, вы, возможно, не захотите пытаться изучить это одновременно с сокетным вводом-выводом.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...