Написание сокет-сервера на Python, рекомендуемые стратегии? - PullRequest
9 голосов
/ 11 марта 2009

Я недавно читал этот документ , в котором перечислен ряд стратегий, которые можно использовать для реализации сокет-сервера. А именно:

  1. Обслужите много клиентов с каждым потоком и используйте неблокирующий ввод-вывод и уведомление о готовности, инициируемое уровнем
  2. Обслужите много клиентов с каждым потоком и используйте неблокирующий ввод-вывод и уведомление об изменении готовности
  3. Обслужите много клиентов с каждым серверным потоком и используйте асинхронный ввод / вывод
  4. обслуживает одного клиента с каждым потоком сервера и использует блокирующий ввод / вывод
  5. Сборка кода сервера в ядре

Теперь я был бы признателен за подсказку, по которой следует использовать в CPython , которая, как мы знаем, имеет некоторые хорошие и некоторые плохие моменты. В основном меня интересует производительность в условиях высокого параллелизма, и да, ряд текущих реализаций слишком медленный.

Так что, если я могу начать с простого, "5" отсутствует, поскольку я не собираюсь взламывать что-либо в ядре.

"4" Также похоже, что это должно быть из-за GIL. Конечно, вы могли бы использовать многопроцессорность вместо потоков, и это дает значительный импульс. Преимущество блокирования ввода / вывода заключается в том, что его легче понять.

И здесь мои знания немного уменьшаются:

«1» - это традиционный выбор или опрос, который можно легко объединить с многопроцессорной обработкой.

«2» - это уведомление о готовности к смене, используемое более новыми системами epoll и kqueue

"3" Я не уверен, что есть какие-либо реализации ядра для этого, которые имеют оболочки Python.

Итак, в Python у нас есть набор отличных инструментов, таких как Twisted. Возможно, это лучший подход, хотя я проверил Twisted и нашел его слишком медленным на многопроцессорной машине. Возможно, 4 витка с балансировщиком нагрузки могут сделать это, я не знаю. Любой совет будет оценен.

Ответы [ 6 ]

7 голосов
/ 11 марта 2009

asyncore - это в основном «1» - он использует select внутри, и у вас есть только один поток, обрабатывающий все запросы. Согласно документам, он также может использовать poll. (РЕДАКТИРОВАТЬ: Удалена ссылка Twisted, я думал, что он использует асинхронно, но я был не прав).

«2» может быть реализовано с помощью python-epoll (просто погуглил - никогда раньше не видел). РЕДАКТИРОВАТЬ: (из комментариев) В python 2.6 модуль select имеет встроенные функции epoll, kqueue и kevent (на поддерживаемых платформах). Таким образом, вам не нужны никакие внешние библиотеки для запуска по краю.

Не исключайте "4", так как GIL будет отброшен, когда поток фактически выполняет или ожидает IO-операций (вероятно, большую часть времени). Это не имеет смысла, если у вас есть огромное количество соединений, конечно. Если у вас есть много обработки, то Python может не иметь смысла ни с одной из этих схем.

Для гибкости, возможно, посмотрите на Twisted ?

На практике ваша проблема сводится к тому, сколько обработки вы собираетесь выполнить для запросов. Если у вас много обработки и вам нужно использовать преимущества многоядерной параллельной работы, то вам, вероятно, понадобится несколько процессов. С другой стороны, если вам просто нужно прослушивать большое количество соединений, выберите select или epoll с небольшим количеством потоков.

3 голосов
/ 11 июля 2010

Одно растворение - это Gevent. Gevent объединяет основанный на libevent опрос событий с облегченным кооперативным переключением задач, реализованным greenlet.

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

(я не знаю, что такое стандартное соглашение об ответе на очень старые вопросы, но решил, что я все равно добавлю свои 2 цента)

3 голосов
/ 11 марта 2009

Как насчет "вилки"? (Я предполагаю, что это то, что делает ForkingMixIn). Если запросы обрабатываются в архитектуре «без общего доступа» (кроме БД или файловой системы), fork () запускается довольно быстро на большинстве * nixes, и вам не нужно беспокоиться обо всех глупых ошибках и осложнениях при работе с потоками.

Потоки - это болезнь дизайна, навязанная нам операционными системами с слишком тяжелыми процессами, ИМХО. Клонирование таблицы страниц с атрибутами копирования при записи кажется небольшой ценой, особенно если вы все равно используете интерпретатор.

Извините, я не могу быть более конкретным, но я больше программист на Perl-переходе на Ruby (когда я не работаю над массами Java на работе)


Обновление: я наконец-то сделал несколько таймингов на нити против форка в свое "свободное время". Проверьте это:

http://roboprogs.com/devel/2009.04.html

Expanded: http://roboprogs.com/devel/2009.12.html

2 голосов
/ 11 марта 2009

Могу ли я предложить дополнительные ссылки?

cogen - это кроссплатформенная библиотека для сетевого ориентированного программирования на основе сопрограмм с использованием расширенных генераторов из python 2.5. На главной странице проекта cogen есть ссылки на несколько проектов с похожей целью.

1 голос
/ 11 марта 2009

Мне нравится ответ Дугласа, но в стороне ...

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

Однако, как упоминал Дуглас, GIL не будет удерживаться во время самых длительных операций ввода-вывода (поскольку не происходит никаких действий с Python-API), поэтому, если вы беспокоитесь о задержке ответа, вы можете попытаться переместить критическое значение. части вашего кода в CPython API.

1 голос
/ 11 марта 2009

http://docs.python.org/library/socketserver.html#asynchronous-mixins

Что касается многопроцессорных (многоядерных) машин. Благодаря CPython из-за GIL вам потребуется как минимум один процесс на ядро ​​для масштабирования. Поскольку вы говорите, что вам нужен CPython, вы можете попробовать сравнить это с ForkingMixIn. С Linux 2.6 может дать некоторые интересные результаты.

Другой способ - использовать Stackless Python . Вот как как ЕВА решила это . Но я понимаю, что это не всегда возможно.

...