Search
Write a publication
Pull to refresh
-1
0
Send message
  1. Это не так. Переключений ровно столько же. Я же давал ссылку на "устаревший" 4.8. Помотрите. Найдите подтверждение своим словам. Но если лень - давайте "от обратного". Вы утверждаете что в варианте Begin*** переключений в три раза больше? Допустим. В таком случае эмпирическим путем установлено, что "цена" одного переключения в случайно взятой (моей) тестовой среде - 74/((3-1)*10000) мс
    или 0,0037мс
    Вас это значение заботит?! Меня - НЕТ ))

  2. Конечно. Только EndAccept выполняется в отдельном потоке обработчике, а не в основном потоке ожидания.

  3. Неправда. Обсуждение начали вы, сказав что вариант с Begin*** - это "лапшеподобный и устаревший функционал" ))

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

По вашей ссылке паттерн Begin/End реализован через TaskToApm класс - так что все сведено к тем же таскам.

/// <summary>
/// Provides support for efficiently using Tasks to implement the APM (Begin/End) pattern.
/// </summary>
internal static class TaskToApm

Но мы правда с вами углубились в какие-то странные сравнения через "количество" кода )) Только вы сравнивая Accept и BeginAccept не учли, что в вашем варианте "дикое количество кода" находится в Task.Run.
Переключения - их количество одинаково. 1 поток ожидания + переключение на поток обработчика.
По поводу задержки - в случае выброшенного исключения при входящем подключении при использовании Accept вы их все будете обрабатывать в основном потоке. В случае с ассинхронным вызовом - только те исключения, которые связаны с невозможность слушающего сокета принять входящее подключение. Но тогда уже и на очередь "по барабану"
PS - Вообще это уже не спор, а холивар какой то. Я запустил простой цикл который подключается и отключается к обработчику ожидания как через Task так и через Begin. Разница на 10000 подключений - 74мс. То есть прикладного смысла в споре нет. А идейный - считайте меня ортодоксом )))

Я заглянул. Загляните и вы.
https://github.com/microsoft/referencesource/blob/master/System/net/System/Net/Sockets/Socket.cs
Сможете со ссылкой на "под капотом" прокомментировать отсутствие задержок? Я не готов, используя работающие функции из коробки, изучать "как это сделано".

И вы правда со вчерашнего вечера убеждаете что это

var Result = Socket.BeginAccept(new AsyncCallback(Accept), Socket);
Result.AsyncWaitHandle.WaitOne();

проще чем это?

var Client = Socket.Accept;
Task.Run(() => Accept(Client));

Наверное это и правда имеет значение. Но не для меня

Я вызываю ассинхронный метод как самый простой, самый быстрый способ передать обработчик входящего соединения в отдельный поток и освободить основной поток для обработки ожидания следующих соединений.
Вызов синхронного метода Accept отдаляет момент передачи обработки как минимум на один шаг. А в реальности больше - ведь при терминировании соединения может произойти исключение - и вам его обрабатывать в основном потоке, задерживая очередь.
Стоп. А с чего вы взяли что блокировка основного потока ожидает ЗАВЕРШЕНИЯ коллбека? Блокировка ожидает сигнала из коллбека. EndAccept в первой же строке коллбека инициирует его а дальше спокойно в отдельном потоке обрабатывает соединение

А вот с таймаутом соглашусь - лишние ложные срабатывания. Убрал у себя, оставив WaitOne()

По какому факту она тут, простите, не используется? ))
Основной поток блокируется в цикле ожидании первого входящего соединения. Нет соединения - что ему еще делать?
Как только оно будет терминировано, срабатывает коллбек-обработчик, который сигнализирует основному потоку, блокировка снимается, снова вызывается BeginAccept и поток снова блокируется в ожидании входящего соединения.

И да, вы как то меняете "вектор атаки" ) Во первых - мы заговорили не об ассинхронности, а о многопоточности. Ассинхронный вызов - способ ее реализации, который я рекомендовал в качестве самого простого. Во вторых - "нормальный сервер должен вызывать операцию Accept в цикле" - и да. основной поток суть есть цикл в котором происходит ассинхронный вызов терминирования соединения. Вы отстаиваете свой вариант - я понимаю. Но я не увидел аргументов ЗА. Я только увидел непонятные ПРОТИВ ))

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

Накосячил. Но цикла это не отменяет. Я хотел продемонстрировать наличие цикла, а не строки кода.
Я пишу на vb.net и у меня сами строки выглядит так

While True
	Dim Result = Socket.BeginAccept(New AsyncCallback(AddressOf Accept), Socket)
	Result.AsyncWaitHandle.WaitOne(AcceptTimeout)
	If Not Result.IsCompleted Then Socket.EndAccept(Result)
End While

Но повторюсь - вполне себе цикл

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

ненене, это вы что то свое придумали )

void OnAccept(IAsyncResult ar) {
var client = socket.EndAccept(ar);
Process(client);
}
Выше - вот так будет выглядет ваш коллбек.

А вот так - обработчик входящих соединений

while (true)
{
  socket.BeginAccept(new AsyncCallback(OnAccept), socket);
}

PS - Извините, я еще с редакторам не разобрался. Но так или иначе - вполне себе цикл, правда )

"лапшеподобный код" в контексте Begin** операций для сокет-объектов - это какой стереотип ради парадигмы, уж простите. А CancelationToken - опять же шашечки или ехать? Если первое - то наверное это серьезный аргумент. А второе - вызовите EndAccept и обработайте исключение.
Я не против трендов. Я за парадигмы. Но прежде всего - я за здравый смысл. А в рекомендации использоваться BeginAccept он заключался в том, что это самый простой, самый стабильный способ получить функционал неблокирующего многопоточного обработчика входящих соединений. Если функционала не хватает - другой разговор. Но в обсуждаемой задаче его как раз "достаточно"

Функция асинхронного вызова с коллбеком в отдельном потоке "из коробки" на 100% удовлетворяющий условию задачи - "старый и неудобный функционал"?! Что же это за тренды такие, где изобретать велосипед, но следуя парадигме, важнее самого велосипеда ))
Но по поводу шишек соглашусь. Я это упомянул - если хотя бы одно из условий присутствует

Для реализации многопоточности достаточно было использовать BeginAccept вместо Accept. Для реализации многопоточного вебсервера - HttpListener вместо socket.
А писать на сокетах в .net свой вебсервер имеет смысл если [есть много времени]/[отсутствуют доступные классы]/[функционала доступных недостаточно].

Information

Rating
Does not participate
Registered
Activity