Socket .Net, реализация сервера
Имею ряд вопросов и идей относительно работы с сокетами в .Net на стороне сервера. Работать можно несколькими способами.
1. Синхронно. Ну тут все понятно. Плохой это вариант в большем числе случаев, так как сильно большой оверхед на операциях ввода\вывода.
2. Асинхронно. Тут есть два варианта, это во первых через паттерн IAsyncResult или же можно использовать SocketAsyncEventArg. Вроде все классно, но я так понимаю, что при большом количестве запросов будет забит весь пул потоков...
3. Не блокирующий ввод\вывод. Это подразумевает использование Socket.Select. Ну вроде все тоже не плохо. Однако как то не понятно. Есть ли у вас, уважаемые, примеры? Я так понимаю, что мы вызываем селект, он нам фильтрует соккеты на предмет готовности к операциям ввода\вывода, потом вызываем синхронно получение\отправку и уже как бы блокировки нет. Могут ошибаться, поправьте если что не так.
Теперь сама модель работы.
1. Слушаем соккет, как появилось соединение, то создаем поток и в нем работаем синхронно. Не лучший вариант, большой оверхед на создание потоков и переключение контекста.
2. Работаем асинхронно, все через колбеки. Есть подозрения, что пул потов будет полностью занят обработкой соединений...
3. Асинхронно слушаем сокет и при приеме нового соединения добавляем в очередь на обработку. При этом работают пару-тройку потоков-воркеров, которые извлекают из очереди соединения и синхронно через селект, то есть без блокировок, обрабатывают их.
Собственно какой вариант предпочтительней? Асинхронный или синхронно с селектом? Может есть свои предложения, советы, дополнения, поправки, опыт? В идеале как всегда хочется молниеносной обработки запросов и 10к соединений.
1. Синхронно. Ну тут все понятно. Плохой это вариант в большем числе случаев, так как сильно большой оверхед на операциях ввода\вывода.
Вы заблуждаетесь - оверхэда никакого нет, просто вызывающий код будет блокирован до завершения операции ввода/вывода.
2. Асинхронно. Тут есть два варианта, это во первых через паттерн IAsyncResult или же можно использовать SocketAsyncEventArg. Вроде все классно, но я так понимаю, что при большом количестве запросов будет забит весь пул потоков...
Наиболее масштабируемое решение реализуется через IAsyncResult, пулы потоков оно не использует (асинхронность сокетов реализована с помощью портов завершения, completion ports).
Он реализуется через IAsyncResult.
1. Слушаем соккет, как появилось соединение, то создаем поток и в нем работаем синхронно. Не лучший вариант, большой оверхед на создание потоков и переключение контекста.
Откуда у вас оверхед? Потоки можно брать из пула (собственного, либо штатного) :) Это нормальное решение, если у вам необходимо обслуживать десяток-другой соединений.
2. Работаем асинхронно, все через колбеки. Есть подозрения, что пул потов будет полностью занят обработкой соединений...
3. Асинхронно слушаем сокет и при приеме нового соединения добавляем в очередь на обработку. При этом работают пару-тройку потоков-воркеров, которые извлекают из очереди соединения и синхронно через селект, то есть без блокировок, обрабатывают их.
Вы измеряли?
Я сделал бы полностью асинхронную обработку без изготовления собственных пулов и провел измерения.
Я это и имел в виду, ну то есть тот факт, что поток простаивает в ожидании операции ввода\вывода. Наверное не совсем верно выразился.
Хм, не знал. Но в любом случае я так понимаю, что колбек то уйдет в пул потоков. К тому же в случае использования completion ports, то интересно как оно поведет себя под моно, в линуксах completion ports нет, но есть epoll... Вы случайно не в курсе как там это все реализовано?
А что можете сказать относительно метода Socket.Select? Есть у Вас опыт его использования?
Затраты на переключение контекста. Если количество одновременных запросов достаточно велико и их обработка занимает время, то получаем большое количество конкурирующих потоков. Если ограничить количество потоков, то получаем модель воркеров, как в апаче реализовано и соответственно нужна очередь соединений к обработке.
Попытался, результат получился странный, асинхронная реализация оказалась хуже чем "по потоку на клиента". Позже попробую повторить эксперимент но уже распределив сервер и клиент по разным машинам, сейчас нет такой возможности.
Фактических этим сейчас и занимаюсь. Просто результаты первых экспериментов не много сбивают с толку.
Хм. Про SocketAsyncEventArgs не знал :) Тесно работал с сокетами еще в .NET 2.0 (его тогда небыло). Похоже что действительно, для высокой нагрузки лучше использовать именно SocketAsyncEventArgs.