Нужно ли использовать асинхронные методы Begin / End, если они уже находятся в отдельном потоке? - PullRequest
6 голосов
/ 20 сентября 2011

Попытка выяснить, следует ли мне использовать асинхронные методы или нет, например:

и

в отличие от их синхронных версий TcpListener.AcceptTcpClient и NetworkStream.Read.Я смотрел на связанные темы, но все еще немного не уверен в одном:

Вопрос: Основное преимущество использования асинхронного метода заключается в том, что графический интерфейс не заблокирован,Однако эти методы будут вызываться в отдельных потоках Task , так как это не угрожает.Кроме того, TcpListener.AcceptTcpClient блокирует поток до тех пор, пока не будет установлено соединение, чтобы не тратить впустую циклы ЦП.Так как это так, то почему многие всегда рекомендуют использовать асинхронные версии?Похоже, что в этом случае синхронные версии будут лучше?

Кроме того, еще один недостаток использования асинхронных методов - повышенная сложность и постоянное приведение объектов.Например, чтобы сделать это:

private void SomeMethod()
{
    // ...

    listener.BeginAcceptTcpClient(OnAcceptConnection, listener);
}

private void OnAcceptConnection(IAsyncResult asyn)
{
    TcpListener listener = (TcpListener)asyn.AsyncState;

    TcpClient client = listener.EndAcceptTcpClient(asyn);
}

В противоположность этому:

TcpClient client = listener.AcceptTcpClient();

Также кажется, что асинхронные версии будут иметь гораздо больше накладных расходов из-зачтобы создать другой поток.(По сути, каждое соединение будет иметь поток, а затем при чтении этого потока также будет иметь другой поток. Threadception!)

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

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

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

Ответы [ 2 ]

4 голосов
/ 20 сентября 2011

TcpListener.AcceptTcpClient блокирует поток до тех пор, пока не будет установлено соединение, поэтому не будет потрачено впустую циклов ЦП.

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

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

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

BeginAcceptTcpClient () использует так называемый обратный вызов завершения ввода-вывода. Во время прослушивания сокета системные ресурсы не используются. Как только поступает запрос на соединение, операционная система запускает APC (асинхронный вызов процедуры), который захватывает поток пула потоков для выполнения обратного вызова. Сам поток обычно используется в течение нескольких микросекунд. Очень эффективно.

Этот вид кода станет намного проще в следующей версии C # со следующими async и await . Может быть, конец года.

3 голосов
/ 20 сентября 2011

Если вы вызываете AcceptTcpClient() в любом потоке , этот поток бесполезен до тех пор, пока не будет установлено соединение.

Если вы наберете BeginAcceptTcpClient(), вызывающий поток может немедленно остановиться, безпотеря потока.

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

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