Асинхронная связь TCP в .NET - PullRequest
       24

Асинхронная связь TCP в .NET

7 голосов
/ 21 февраля 2009

Быстрый вопрос: есть ли очевидное преимущество в использовании асинхронной связи с классом NetworkStream (генерируемым TcpClient), т. Е. Методами BeginRead / BeginWrite вместо запуска отдельного потока и использования синхронных операций с ним, т. Е. Чтения / записи? У меня сложилось впечатление (это может быть совершенно неправильно), что асинхронные операции неблокируемы и выполняются на уровне операционной системы (возможно, в стеке TCP?) С элементом пула потоков для обратного вызова. Я думаю, что он, безусловно, должен отличаться от вызова ThreadPool.QueueUserWorkItem в синхронном методе, иначе в его предоставлении будет довольно мало смысла. Теперь я вполне уверен, что такого рода вещи (вызовы уровня ОС) происходят, по крайней мере, для файлового ввода-вывода, но если кто-то может прояснить вопрос, касающийся связи по сети (TCP), это было бы очень полезно. По сути, я хотел бы знать, есть ли какая-либо конкретная выгода для любого метода (помимо очевидной возможности использования классов BinaryReader / StreamReader с синхронными вызовами).

Ответы [ 4 ]

10 голосов
/ 21 февраля 2009

Существует разница: если вы используете рабочий поток для вызова синхронной версии, вы связываете один из потоков блокирующим вызовом.

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

1 голос
/ 21 февраля 2009

Я не совсем уверен, почему NetworkStream даже имеет BeginRead / Write, так как это в основном нарушает назначение NetworkStream в первую очередь. Используя асинхронные методы, вы получаете более быстрый отклик, большую масштабируемость и снижение потребления ресурсов.

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

1 голос
/ 21 февраля 2009

Я согласен с AnthonyWJones, представьте, что в вашем пуле потоков 10 потоков, но у вас есть 100 пассивных клиентов. С асинхронными вызовами вы можете BeginRead для каждого из них, и когда данные от кого-либо будут готовы, они будут обработаны одним из потоков пула. Но если вы попытаетесь использовать QueueUserWorkItem, вы запланируете получение данных только от 10 клиентов. И если они ничего не отправляют в течение 1 часа, другие 90 клиентов никогда не получат возможность получить данные.

1 голос
/ 21 февраля 2009

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

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

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

Асинхронный:

  1. Вы звоните в BeginRead / BeginWrite
  2. «Система» (framework / OS) информируется о том, что вы хотите
  3. Чтение / запись завершено
  4. «Система» сообщает потоку в пуле потоков, чтобы он вызывал ваш обратный вызов
  5. Вы делаете все, что нужно для завершения операции

Синхронно в другом потоке:

  1. Вы получаете поток из пула потоков для обработки ввода-вывода
  2. Вы звоните, чтобы прочитать / написать
  3. «Система» (framework / OS) информируется о том, что вы хотите
  4. Чтение / запись завершено
  5. Вы делаете все, что нужно для завершения операции

Единственное отличие здесь заключается в том, что шаг 4 из асинхронного вызова становится шагом 1 в синхронном случае в другом потоке.

...