Подтвердить что ты не робот

Win32 Overlapped I/O - Процедуры завершения или WaitForMultipleObjects?

Мне интересно, какой подход быстрее и почему?

При написании сервера Win32 я много читал о портах завершения и перекрывающемся вводе-выводе, но я ничего не читал, чтобы предположить, какой набор API дает наилучшие результаты на сервере.

Должен ли я использовать процедуры завершения или использовать API WaitForMultipleObjects и почему?

4b9b3361

Ответ 1

Вы предлагаете два метода выполнения перекрытия ввода-вывода и игнорируете третий (или я не понимаю ваш вопрос).

Если вы выполняете перекрываемую операцию, WSARecv(), вы можете указать структуру OVERLAPPED, которая содержит событие, и вы можете подождать для того, чтобы это событие было сообщено, чтобы указать, что перекрытие ввода-вывода завершено. Это, я полагаю, является вашим подходом WaitForMultipleObjects(), и, как уже упоминалось ранее, это не масштабируется хорошо, так как вы ограничены количеством дескрипторов, которые вы можете передать в WaitForMultipleObjects().

В качестве альтернативы вы можете передать процедуру завершения, которая вызывается при завершении завершения. Это называется "предупреждающим вводом-выводом" и требует, чтобы поток, выдавший вызов WSARecv(), находился в "предупреждающем" состоянии для вызываемой процедуры завершения. Потоки могут оказаться в аварийном состоянии несколькими способами (вызов SleepEx() или различных версий EX функций Wait и т.д.). книга Рихтера, которую я открываю передо мной, говорит: "Я довольно часто работал с предупреждающим вводом-выводом, и я буду сначала сообщите вам, что аварийный ввод-вывод ужасен и его следует избегать". Достаточно сказал ИМХО.

Третий способ, прежде чем вызывать вызов, вы должны связать дескриптор, с которым вы хотите перекрывать ввод-вывод, с портом завершения. Затем вы создаете пул потоков, которые обслуживают этот порт завершения, вызывая GetQueuedCompletionStatus() и цикл. Вы выдаете WSARecv() с структурой OVERLAPPED БЕЗ события в нем, и когда завершение ввода-вывода завершается, выдается из GetQueuedCompletionStatus() в одном из потоков пула ввода-вывода и может обрабатываться там.

Как уже упоминалось ранее, Vista/Server 2008 очистили работу IOCP и устранили проблему, из-за которой вы должны были убедиться, что поток, который выдал перекрывающийся запрос, продолжал работать до завершения запроса. Ссылка на ссылку на это можно найти здесь. Но в любом случае эту проблему легко обойти; вы просто привязываете WSARecv к одному из потоков пула ввода-вывода, используя тот же IOCP, который вы используете для завершений...

Во всяком случае, ИМХО, использующее IOCP, - лучший способ сделать перекрывающиеся операции ввода-вывода. Да, если вы начнете использовать наложенную/асинхронную природу вызовов, это может занять немного времени на старте, но это стоит того, что система очень хорошо масштабируется и предлагает простой метод "огонь и забыть" для работы с перекрывающимися операциями.

Если вам нужен какой-то пример кода, который вы собираетесь делать, у меня есть несколько статей о написании систем ввода-вывода IO и куча свободного кода, который обеспечивает реальную структуру для высокопроизводительных серверов; см. здесь.

В стороне; IMHO, вы действительно должны прочитать "" Windows Via C/С++ (PRO-Developer)" Джеффри Рихтера и Кристофа Насарра, поскольку он касается всего, что вам нужно знать о перекрывающихся вводах-выводах и большинстве других передовых технологий платформы Windows и API.

Ответ 2

WaitForMultipleObjects ограничено 64 ручками; в сильно параллельном приложении это может стать ограничением.

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

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

Я бы не ожидал существенной разницы в производительности, но в конце вы можете только сделать свои собственные измерения, чтобы отразить ваше использование. Обратите внимание, что Vista/Server2008 внесла изменения с портами завершения, которые теперь не нужны для создания операций ввода-вывода, это может иметь большее значение (см. Эту статью статья Марк Руссинович).

Ответ 3

Таблица 6-3 в книге "Сетевое программирование для Microsoft Windows, 2-е издание" сравнивает масштабируемость перекрываемых операций ввода-вывода через порты завершения и другие методы. Завершающие порты выдувают все другие модели ввода-вывода из воды, когда речь идет о пропускной способности, при использовании гораздо меньшего количества потоков.

Ответ 4

Разница между портами завершения WaitForMultipleObjects() и I/O заключается в том, что IOCP масштабируется до тысяч объектов, тогда как WFMO() не используется и не должен использоваться для чего-либо большего, чем 64 объекта (хотя вы могли бы).

Вы не можете действительно сравнить их для производительности, поскольку в домене < 64 объекта, они будут по существу идентичными.

WFMO(), однако, выполняет циклическое на своих объектах, поэтому занятые объекты с низкими номерами индексов могут голодать объектами с высокими номерами индексов. (Например, если объект 0 постоянно уходит, он будет голодать объекты 1, 2, 3 и т.д.). Это явно нежелательно.

Я написал библиотеку IOCP (для сокетов), чтобы решить проблему C10K и поместить ее в общедоступное. Я смог на 512 Мб W2K-машине получить 4000 сокетов одновременно с передачей данных. (Вы можете получить гораздо больше сокетов, если они неактивны - занятый сокет потребляет больше не выгружаемого пула и максимальный предел в отношении того, сколько сокетов вы можете иметь).

http://www.45mercystreet.com/computing/libiocp/index.html

API должен предоставить вам именно то, что вам нужно.

Ответ 5

Не уверен. Но я использую WaitForMultipleObjects и/или WaitFoSingleObjects. Это очень удобно.

Ответ 6

Любая рутина работает, и я действительно не думаю, что кто-то значительно быстрее, чем другой.

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

Я лично считаю, что подход WaitForMultipleObjects() приводит к более чистым кодам и более безопасным потокам.