Сокет BeginConnect Синхронное выполнение обратного вызова в .NET Core 2.2 - PullRequest
0 голосов
/ 15 марта 2019

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

Речь идет о выполнении вызова mySocket.BeginConnect и его вызове предоставленного AsyncCallback.,С некоторым тестовым проектом для сетевого взаимодействия, я вижу, что для того же кода предоставляемый обратный вызов иногда вызывается синхронно во время выполнения BeginConnect, а иногда асинхронно (BeginConnect уже возвращал IASyncResult до завершения обратного вызова), причем последний случай является наиболее распространенным(80% - 90% случаев).

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

Я проверил исходный код платформы .NET Core 2.2 и увидел, что базовый класс LazyAsyncResult имеет два конструктора, один из которых вызывает синхронный вызов в своем конструкторе.Тем не менее, я не нашел ни одного случая, когда этот конструктор используется фреймворком.Кажется, что вызовы, которые я выполнял с помощью отладчика, всегда создают ContextAwareResult, у которого есть только вызов базового конструктора для другого конструктора.Я могу в некоторых из этих тестовых случаев также ясно видеть в отладчике, что свойство CompletedSynchronously возвращает true.

Любые подсказки, в каком сценарии этот обратный вызов вызывается синхронно и почему?

Cheers.

Редактировать:

  • Тестирование проводилось в Windows 10.
  • Точно такой же код в полной среде .NET 4.6.2 делает создание всегда асинхронным.

1 Ответ

0 голосов
/ 15 марта 2019

Вы не указали ОС, которую используете для тестов, но в случае, если это Windows (для не-Windows я бы сказал с высокой степенью уверенности, что поведение должно быть схожим), это ожидаемое поведение асинхронных операций ввода-вывода.,В частности, не гарантируется, что запрос асинхронного ввода-вывода всегда завершается асинхронно.Когда это возможно, диспетчер ввода-вывода пытается сократить путь операций ввода-вывода по очевидным причинам (хорошим примером являются быстрые операции ввода-вывода, которые обходят типичный поток ввода-вывода через драйверы устройств и обмениваются данными непосредственно с диспетчером памяти - это в основном дляфайловые операции, которые могут быть обналичены).В этом случае результат может быть возвращен в одном и том же потоке независимо от того, что операция запрашивается как асинхронная.Для сетевого ввода-вывода такое поведение чаще всего встречается для операций чтения (для случаев, когда данные уже считаны во внутренний буфер), реже для операций записи (для TCP в основном для случаев с включенным Nagle или отложенным ACK при завершенииоперация вывода не требует ожидания пакета ACK).Что касается сценария с открытием соединения TCP, то это возможно, когда процедура рукопожатия TCP пропускает сетевой уровень, как в случае с опцией SIO_LOOPBACK_FAST_PATH (см. здесь и здесь для получения дополнительной информации), которые, однако, могут использоватьсятолько для сокетов интерфейса loopback (localhost).

. Асинхронность ввода / вывода .NET построена на основе собственных механизмов ввода / вывода и наследует свойства и поведение этих механизмов.

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