2011-01-13 3 views
2

Предположим, у нас есть приложение для обмена мгновенными сообщениями, основанное на клиент-сервере, а не p2p. Фактический протокол не имеет значения, важна архитектура сервера. Указанный сервер может быть закодирован для работы в однопоточном, непараллельном режиме с использованием неблокирующих сокетов, которые по определению позволяют нам выполнять операции, такие как чтение-запись, эффективно сразу (или мгновенно). Эта особенность неблокирующих сокетов позволяет нам использовать какую-то функцию выбора/опроса в самом ядре сервера и тратить время от времени на фактические операции чтения/записи сокетов, а тратить время на обработку всей этой информации , Правильно закодированный, это может быть очень быстро, насколько я понимаю. Но есть второй подход, и это многопоточно, создавая новый поток (очевидно, используя какой-то пул потоков, поскольку эта операция может быть (очень) медленной на некоторых платформах и при некоторых обстоятельствах) и разрешать эти потоки работать параллельно, в то время как основной фоновый поток обрабатывает accept() и прочее. Я видел, как этот подход объяснялся в разных местах по Сети, поэтому он, очевидно, существует.Разработка сервера мгновенных сообщений

Теперь вопрос в том, что если у нас есть неблокирующие сокеты, а также немедленные операции чтения/записи и простой, легко закодированный дизайн, почему существует второй вариант? Какие проблемы мы пытаемся преодолеть с помощью второго проекта, то есть потоков? AFAIK они обычно используются для работы над медленными и, возможно, блокирующими операциями, но таких операций, похоже, там нет!

ответ

1

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

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

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

Кроме того, это может помочь преодолеть ограничения ОС. Пути ввода-вывода в ядре могут быть более распределены между обработчиками. Не все операционные системы могут полностью вносить поток ввода-вывода из однопоточных приложений. Еще в старые времена не было никаких больших альтернатив старой * nix select(), которая обычно имела ограничение filedesciptor 1024, и аналогичные API-интерфейсы сильно начали унижать, как только вы сказали, что он контролирует слишком много сокетов. Распространение всех этих клиентов на несколько потоков или процессов помогло преодолеть этот предел.

В течение 1: отображение 1 между нитями, есть несколько причин для реализации этой архитектуры:

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

  • API-интерфейсы блокировки поддержки. Они повсюду. Когда поток обрабатывает много/всех клиентов, а затем выполняет блокирующий вызов в базе данных, он будет останавливать всех. Даже файлы чтения могут блокировать ваше приложение, и вы обычно не можете контролировать обычные дескрипторы файлов/дескрипторы для событий ввода-вывода - или, когда это возможно, модель программирования часто исключительно сложна.

Недостаток здесь не будет масштабироваться, по крайней мере, не с наиболее широко используемыми языками/каркасом.Наличие тысяч собственных потоков может повредить производительность. Хотя некоторые языки предлагают гораздо более легкий подход, например, Erlang и в некоторой степени Go.

+0

На самом деле, я имел в виду ТОЧНО, что 1: 1 клиент: дизайн отображения нитей. Гибридный дизайн, о котором вы говорили, имеет смысл, и я действительно знаком с ним. Не могли бы вы подробнее рассказать о дизайне 1: 1? – iksemyonov

+0

Спасибо !!! Я могу добавить только «волокна Win32» здесь, нет? Это единственный легкий (как в действительно легком) API-интерфейсе, который я знаю. Но в целом, да, то, что вы говорите, имеет смысл. Как вы избегаете блокировки вызовов базы данных (это самая очевидная вещь, которая сразу приходит в голову в контексте этого обсуждения и, кроме того, потоков) в однопоточной модели? – iksemyonov

+0

волокна могут быть легкими, но они не спасают вас, если вы хотите сделать блокирующий вызов. Избежать блокировки вызовов обычно практически невозможно, поэтому модель 1: 1 настолько распространена. Некоторые API БД предоставляют неблокирующие вызовы, а большинство нет. В последнем случае вы можете реализовать асинхронный шаблон и запланировать блокирующий вызов в потоке (пуле) и получить уведомление, когда оно будет завершено. Это означает, что вы наберете много клиентов на (меньше) потоков, обрабатывающих блокирующие вызовы, хорошо ли это работает, зависит от скорости блокировки вызовов и среднего времени, которое требуется каждому. – nos

Смежные вопросы