Некоторое уточнение, необходимое для синхронных и асинхронных операций asio

Насколько я знаю, основное различие между синхронными и асинхронными операциями. То есть write() или read() vs async_write() и async_read() - это то, что первые не возвращаются до завершения операции или ошибки, а последние возвращаются немедленно.

В связи с тем, что асинхронные операции контролируются io_service.run(), которые не заканчиваются до тех пор, пока не будут завершены контролируемые операции. Мне кажется, что в последовательных операциях, связанных с соединениями TCP/IP с протоколами, такими как POP3, в которых операция представляет собой последовательность, такую ​​как:

 C: <connect>
 S: Ok.
 C: User...
 S: Ok.
 C: Password
 S: Ok.
 C: Command
 S: answer
 C: Command
 S: answer
 ...
 C: bye
 S: <close>

Разница между синхронными/асинхронными операторами не имеет большого смысла.

Конечно, в обеих операциях всегда существует риск того, что программный поток бесконечно прекратится в каком-то обстоятельстве - при использовании таймеров - но я хотел бы узнать еще несколько авторизованных мнений в этом вопросе.

Я должен признать, что вопрос довольно нечеткий, но я хотел бы услышать некоторые советы о том, когда использовать тот или иной. У меня возникли проблемы при отладке с MS Visual Studio относительно асинхронных операций SSL в клиенте POP3, на котором я сейчас работаю, и иногда думаю, что, возможно, это плохая идея, использующая асинхронную функцию.

Ответ 1

Документация Boost.Asio действительно делает фантастическую работу, объясняющую эти две концепции. Как Ральф упомянул, У Криса также есть отличный блог, описывающий асинхронные концепции. парковочный счетчик пример, объясняющий, как работает тайм-аут, так же как и bind проиллюстрирован.

Сначала рассмотрим операцию синхронного подключения:

synchronous connect

Управляющий поток здесь довольно прост, ваша программа вызывает некоторый API (1) для подключения сокета. API использует службу ввода-вывода (2) для выполнения операции в операционной системе (3). По завершении этой операции (4 и 5) управление сразу же возвращается к вашей программе (6) с некоторыми признаками успеха или сбоя.

Аналогичная асинхронная операция имеет совершенно другой поток управления:

asynchronous connect

Здесь ваше приложение инициирует операцию (1), используя ту же службу ввода-вывода (2), но поток управления инвертируется. Завершение операции заставляет службу ввода-вывода уведомлять вашу программу через обработчик завершения. Время между шагом 3 и завершением операции полностью содержалось в операции подключения для синхронного случая.

Вы можете видеть, что синхронный случай, естественно, проще для большинства программистов, потому что он представляет собой традиционные парадигмы потока управления. Перевернутый поток управления, используемый асинхронными операциями, трудно понять, он часто заставляет вашу программу разделять операции на методы start и handle, где логика смещается. Однако, как только у вас будет базовое понимание этого потока управления, вы поймете, насколько мощна концепция на самом деле. Некоторые преимущества асинхронного программирования:

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

  • Повышенная производительность. Конструкция нить за соединение просто не масштабируется. См. проблема C10K.

  • Состав (или цепочка). Операции более высокого уровня могут состоять из нескольких обработчиков завершения. Рассмотрите возможность переноса изображения JPEG, протокол может определять, что первые 40 байтов включают заголовок, описывающий размер изображения, форму, а может быть, некоторую другую информацию. Первый обработчик завершения отправки этого заголовка может инициировать вторую операцию для отправки данных изображения. Операция sendImage() более высокого уровня не должна знать или заботиться о цепочке методов, используемой для реализации передачи данных.

  • Время ожидания и отмена. Существуют определенные платформы для тайм-аута продолжительной работы (например: SO_RCVTIMEO и SO_SNDTIMEO). Использование асинхронных операций позволяет использовать deadline_timer отмену длительных операций на всех поддерживаемых платформах.


Конечно, в обеих операциях есть всегда риск того, что поток программы бесконечно останавливается кругооборотом - использование таймеры-, но я хотел бы знать некоторые более авторизованные мнения в этом дело.

Мой личный опыт использования Asio связан с аспектом масштабируемости. Написание программного обеспечения для суперкомпьютеров требует достаточной осторожности при работе с ограниченными ресурсами, такими как память, потоки, сокеты и т.д. Использование потока -соединение для ~ 2 миллионов одновременных операций - это проект, который мертв по прибытии.

Ответ 2

Я полагаю, что выбор синхронного/асинхронного очень специфичен для приложения. Я согласен с тем, что асинхронная парадигма может сделать код, а также отладки намного сложнее, но имеет свои преимущества.

Чтобы проиллюстрировать, основная причина, по которой мы переключились с синхронного ввода-вывода на повышение asio с использованием async IO, заключается в том, что в нашем приложении блокирование ввода-вывода было просто не вариантом, у нас есть мультимедийный потоковый сервер, в котором я транслировал мультимедийные пакеты нескольким клиентам после кодирования. Проблема заключалась в том, что проблемы с сетью привели к тому, что весь конвейер передачи-кодирования-доставки был эффективно остановлен (например, если соединение с одним клиентом не удалось).

Подводя итог, в моем (ltd) опыте с асинхронным IO он может быть полезен в ситуациях, когда у вас есть другая работа, которую нужно выполнить, пока вы ждете завершения ввода-вывода (например, для обслуживания других клиентов и т.д.). В системах или сценариях, где вам нужно дождаться, когда результат ввода-вывода будет продолжен, было бы намного проще использовать синхронный ввод-вывод.

Это также имеет смысл в дуплексных системах связи (например, более сложные протоколы, такие как SIP, RTSP, где клиент и сервер могут отправлять запросы). Прошло некоторое время с тех пор, как я занимался POP, но для простого обмена в вашем примере async IO можно было считать излишним. Я бы переключился на async IO только один раз, когда был уверен, что синхронизации IO недостаточно для удовлетворения моих требований.

WRT для документации asio asio, я обнаружил, что лучший способ получить поддержку - это работать с примерами. Кроме того, ссылка, которую вы, возможно, захотите проверить, - http://en.highscore.de/cpp/boost/index.html Она получила действительно приятную главу о повышении asio. Также блог Chris Kohlhoff (автор asio) имеет некоторые действительно отличные статьи, заслуживающие проверки.

Ответ 3

Простой ответ: (цитата из здесь с небольшими изменениями)

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

В ASync все происходит одновременно. Обычно многопоточные приложения, которые одновременно выполняют несколько задач.