2009-03-11 2 views
9

Я недавно читал this document, в котором перечислены некоторые стратегии, которые могут быть использованы для реализации сервера сокетов. А именно, они:Написание сервера на основе сокетов в Python, рекомендуемые стратегии?

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

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

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

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

И здесь мои знания убывание немного:

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

«2» является уведомлением готовности смены, используемый новой Epoll и Kqueue

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

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

ответ

7

asyncore в основном «1» - он использует select внутренне, и у вас только один поток, обрабатывающий все запросы. Согласно документам, он также может использовать poll. (EDIT: Удаленная ссылка Twisted, я думал, что она используется asyncore, но я был неправ).

«2» может быть реализован с помощью python-epoll (только в Google - он никогда не видел его раньше). EDIT: (из комментариев) В python 2.6 select module имеет встроенный epoll, kqueue и kevent (на поддерживаемых платформах). Таким образом, вам не нужны внешние библиотеки для выполнения обслуживания с краем.

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

Для гибкости можно взглянуть на Twisted?

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

+0

Я думаю, что epoll находится в stdlib в версии 2.6+ и easy_installable для 2.5. Пакет называется select-something. Извините за неопределенность. –

+0

Twisted может также использовать epoll. Фактически, Twisted превращает все поддерживаемые API уведомлений о событиях в единый API, который он представляет вам. Поэтому, если лучше всего подходит платформа, выберите, ваше приложение использует select. Если у вас есть epoll, ваше приложение использует epoll. Все прозрачно для вас. –

+0

Это написано 'asyncore' – new123456

1

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

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

Другой способ - использовать Stackless Python. Это how EVE solved it. Но я понимаю, что это не всегда возможно.

+0

Спасибо, но вы протестировали эти вещи? Они медленные. Я бы не изобрел колесо, если бы мне не пришлось. –

+0

+1 stackless/EVE, но я сказал CPython –

1

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

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

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

2

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

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

3

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

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

К сожалению, я не могу быть более конкретным, но я больше программист Perl-Переход-на-Руби (когда я не следящая над массами Java на работе)


Update : Я, наконец, сделал некоторые тайминги в вилке vs fork в мое «свободное время». Проверьте это:

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

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

+0

Кроме того, вы можете использовать код для других модулей, которые, как вы знаете, вы будете использовать, прежде чем запускать дочерние процессы. Это предотвратит их повторное использование (JIT-ed, независимо). Во-вторых, сохраните данные в родительском малом, используйте «exit» в качестве супер-сборщика мусора. – Roboprog

3

Один гуманного является GEvent. Gevent выдает участие в опросе, посвященном событиям на основе libevent, с легким совместным переключением задач, реализованным с помощью greenlet.

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

(я не знаю, что SO конвенции об ответе на НАСТОЯЩЕМУ старые вопросы есть, но решил, что я бы еще добавить мои 2 цента)