В чем разница между WaitForMultipleObjects и boost :: asio для нескольких окон :: basic_handle? - PullRequest
5 голосов
/ 01 июня 2011

У меня есть список РУЧКИ, управляемый множеством различных устройств ввода-вывода. Какая разница (производительность) между:

  1. вызов WaitForMultipleObjects для всех этих дескрипторов
  2. async_read на boost :: windows :: basic_handle вокруг всех этих дескрипторов

Является ли WaitForMultipleObjects O (n) комплексом времени с n количеством дескрипторов?
Вы можете как-то вызвать async_read на windows :: basic_handle, верно? Или это предположение неверно?
Если я вызову запуск на одном и том же устройстве ввода-вывода в нескольких потоках, будут ли обрабатываться вызовы обработки между этими потоками? Это было бы основным преимуществом использования asio.

Ответы [ 2 ]

10 голосов
/ 06 июня 2011

, поскольку это звучит так, как если бы вы использовали asio в качестве основного использования, это тот факт, что он построен поверх портов завершения ввода-вывода (для краткости iocp). Итак, начнем со сравнения iocp с WaitForMultipleObjects(). Эти два подхода по сути такие же, как select против epoll в linux.

Основным недостатком WaitForMultipleObjects, который был решен с помощью iocp, является невозможность масштабирования со многими дескрипторами файлов. Это O (n), поскольку для каждого полученного вами события вы снова передаете полный массив, и внутренне WaitForMultipleObjects должен сканировать массив, чтобы узнать, какие дескрипторы активировать.

Тем не менее, это редко проблема из-за второго недостатка. WaitForMultipleObjects() имеет ограничение на максимальное количество дескрипторов, которые он может ожидать (MAXIMUM_WAIT_OBJECTS). Это ограничение составляет 64 объекта (см. Winnt.h). Существуют способы обойти это ограничение, создавая объекты Event и привязывая несколько сокетов к каждому событию, а затем ожидая 64 события.

Третий недостаток состоит в том, что в WaitForMultipleObjects() есть небольшая ошибка. Возвращает индекс дескриптора, который вызвал событие. Это означает, что он может передать только одно событие обратно пользователю. Это отличается от select, который возвращает все файловые дескрипторы, которые вызвали событие. WaitForMultipleObjects сканирует переданные ей дескрипторы и возвращает первый дескриптор, в котором было поднято событие.

Это означает, что, если вы ожидаете 10 очень активных сокетов, большинство из которых имеют события на них большую часть времени, будет очень сильный уклон в сторону обслуживания первого сокета в списке, переданном в WaitForMultipleObjects , Это можно обойти, каждый раз, когда функция возвращается и событие обслуживается, запускайте его снова с таймаутом 0, но на этот раз только в той части массива 1, которая прошла после инициирующего события. Неоднократно, пока не будут посещены все маркеры, затем вернитесь к исходному вызову со всеми маркерами и фактическим таймаутом.

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

С iocp (и, следовательно, asio):

  1. Вы не повторяете, какие дескрипторы вас интересуют, вы говорите Windows один раз, и он запоминает это. Это означает, что он намного лучше масштабируется с помощью множества ручек.
  2. У вас нет ограничения на количество дескрипторов, которые вы можете подождать
  3. Вы получаете каждое событие, то есть нет предвзятого отношения к какой-либо конкретной ручке

Я не уверен, что вы предполагаете использовать async_read для пользовательского дескриптора. Возможно, вам придется проверить это. Если ваш дескриптор ссылается на сокет, я думаю, он будет работать.

Что касается вопроса о потоках; да. Если вы run() io_service в нескольких потоках, события отправляются в свободный поток и будут масштабироваться с большим количеством потоков. Это особенность iocp, которая даже имеет API пула потоков.

Вкратце: я полагаю, что asio или iocp обеспечат лучшую производительность, чем простое использование WaitForMultipleObjects, но то, принесет ли вам эта производительность пользу, зависит в основном от того, сколько у вас ручек и насколько они активны.

1 голос
/ 08 марта 2019

Обе WaitForSingleObject и WaitForMultipleObjects являются широко используемыми функциями. Функция WaitForSingleObject используется для ожидания одного объекта синхронизации потока. Это сигнализируется, когда объект настроен на сигнал или интервал ожидания истек. Если временной интервал бесконечен, он ждет бесконечно.

DWORD WaitForSingleObject(
  HANDLE hHandle,
  DWORD  dwMilliseconds
);

WaitForMultipleObjects используется для ожидания сигналов нескольких объектов. В объекте синхронизации потока семафоров, когда счетчики обнуляются, объект не сигнализируется. Событие автоматического сброса и Mutex не сигнализируются, когда он освобождает объект. Событие ручного сброса влияет на состояние функций ожидания.

DWORD WaitForMultipleObjects(
  DWORD        nCount,
  const HANDLE *lpHandles,
  BOOL         bWaitAll,
  DWORD        dwMilliseconds
);

Если dwMilliseconds равно zero, функция не переходит в состояние ожидания, если объект не передан; это всегда возвращается немедленно. Если dwMilliseconds равно INFINITE, функция вернется только при сигнале объекта.

...