2009-03-11 17 views
9

Hace poco estuve leyendo this document que enumera una serie de estrategias que podrían emplearse para implementar un servidor de socket. Es decir, ellos son:Escribir un servidor basado en socket en Python, ¿estrategias recomendadas?

  1. servir a muchos clientes con cada hilo, y el uso sin bloqueo de E/S y la notificación disposición disparado por nivel
  2. servir a muchos clientes con cada hilo, y el uso sin bloqueo O y la disposición de notificación de cambio de E/
  3. servir a muchos clientes con cada hebra del servidor, y utilizar e/S asíncrona
  4. servir a un cliente con cada hebra del servidor, y utilizar el bloqueo de e/S
  5. Construir el código del servidor en el núcleo

Ahora, agradecería una pista sobre la cual debería usarse en CPython, que sabemos tiene algunos puntos buenos y algunos puntos malos. Estoy interesado principalmente en el rendimiento bajo alta concurrencia, y sí, varias implementaciones actuales son demasiado lentas.

Así que si empiezo con el fácil, "5" está fuera, ya que no voy a piratear nada en el kernel.

"4" También parece que debe estar fuera debido a la GIL. Por supuesto, podría usar multiprocesamiento en lugar de hilos aquí, y eso da un impulso significativo. El bloqueo de IO también tiene la ventaja de ser más fácil de entender.

Y aquí mi conocimiento se desvanece un poco:

"1" es tradicional de selección o un sondeo que podría ser trivialmente combina con multiprocesamiento.

"2" es la notificación de cambio de la disposición, que utiliza el nuevo epoll y kqueue

"3" No estoy seguro de que hay cualquier implementación del kernel para este que tienen envolturas de Python.

Por lo tanto, en Python tenemos una bolsa de herramientas geniales como Twisted. Tal vez sean un mejor enfoque, aunque he comparado Twisted y lo encontré demasiado lento en una máquina con múltiples procesadores. Tal vez tener 4 torceduras con un equilibrador de carga podría hacerlo, no lo sé. Cualquier consejo sería apreciado.

Respuesta

7

asyncore es básicamente "1" - Utiliza select internamente, y solo tiene un hilo que maneja todas las solicitudes. De acuerdo con los documentos, también puede usar poll. (EDITAR: Se eliminó la referencia Twisted, pensé que se usaba asyncore, pero estaba equivocado).

"2" podría implementarse con python-epoll (solo lo busqué en Google, nunca antes lo había visto). EDITAR: (a partir de los comentarios) En python 2.6 select module tiene epoll, kqueue y kevent built-in (en plataformas compatibles). Por lo tanto, no necesita ninguna biblioteca externa para realizar una publicación activada por el borde.

No descarte "4", ya que GIL se eliminará cuando un subproceso está realmente en curso o esperando operaciones IO (probablemente la mayor parte del tiempo). No tiene sentido si tienes una gran cantidad de conexiones, por supuesto. Si tienes que procesar mucho, entonces python puede no tener sentido con ninguno de estos esquemas.

Para mayor flexibilidad, puede consultar Twisted?

En la práctica, su problema se reduce a la cantidad de procesamiento que va a hacer para las solicitudes. Si tiene mucho procesamiento y necesita aprovechar la operación paralela de múltiples núcleos, entonces probablemente necesite múltiples procesos. Por otro lado, si solo necesita escuchar en muchas conexiones, seleccione o epoll, con un pequeño número de subprocesos debería funcionar.

+0

Creo que epoll está en el stdlib en 2.6+, y easy_installable para 2.5. El paquete se llama select-something. Perdón por la vaguedad. –

+0

Twisted también puede usar epoll. De hecho, Twisted convierte todas las API de notificación de eventos admitidas en una API uniforme que te presenta. Entonces, si lo mejor que puede hacer la plataforma es seleccionar, su aplicación usa select. Si tiene epoll, tu aplicación usa epoll. Todo de forma transparente para ti. –

+0

Se deletrea 'asyncore' – new123456

1

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

cuanto a máquinas multi-procesador (multi-núcleo). Con CPython debido a GIL, necesitará al menos un proceso por núcleo para escalar. Como dice que necesita CPython, puede tratar de compararlo con ForkingMixIn. Con Linux 2.6 podría dar algunos resultados interesantes.

Otra forma es usar Stackless Python. Eso es how EVE solved it. Pero entiendo que no siempre es posible.

+0

Gracias, pero ¿ha referenciado esas cosas? Ellos son lentos No inventaría la rueda si no fuera necesario. –

+0

+1 sin pilas/EVE, pero dije CPython –

1

I como respuesta Douglas', sino como un aparte ...

Se puede usar un hilo de expedición/proceso centralizado que recibe las notificaciones de preparación utilizando select y los delegados a un grupo de subprocesos de trabajo/processes Para ayudar a lograr sus metas de paralelismo

Como mencionó Douglas, sin embargo, el GIL no se retendrá durante las operaciones de E/S más largas (ya que no están sucediendo cosas Python-API), por lo que si le preocupa latencia puede intentar mover el porciones críticas de su código para CPython API.

2

¿Puedo sugerir enlaces adicionales?

cogen es una biblioteca de plataforma cruzada para la programación basada en coroutine orientada a la red que utiliza los generadores mejorados de python 2.5. En la página principal del proyecto de cogeneración hay enlaces a varios proyectos con un propósito similar.

3

¿Qué tal "tenedor"? (Supongo que eso es lo que hace ForkingMixIn) Si las solicitudes se manejan en una arquitectura de "nada compartido" (que no sea DB o sistema de archivos), fork() comienza bastante rápido en la mayoría de * nixes, y no tiene que preocuparse sobre todos los errores tontos y las complicaciones de enhebrar.

Los hilos son una enfermedad de diseño forzada por los sistemas operativos con procesos de peso demasiado pesado, en mi humilde opinión. La clonación de una tabla de páginas con atributos de copiar-escribir parece un precio bajo, especialmente si está ejecutando un intérprete de todos modos.

Lo siento, no puedo ser más específico, pero yo soy más de un programador de Perl-transición-a-Rubí (cuando no estoy trabajando sin parar con masas de Java en el trabajo)


Actualizar : Finalmente hice algunos tiempos en el hilo frente a la bifurcación en mi "tiempo libre". Compruébelo usted mismo:

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

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

+0

Además, podría obtener el código de otros módulos que sabe que usará antes de iniciar los procesos secundarios. Esto evitará que sean tokenizados (JIT-ed, lo que sea) una y otra vez. Segundo, mantenga los datos en el padre pequeño, use "exit" como un super recolector de basura. – Roboprog

3

Una sollution es GEvent. Gevent combina una encuesta de eventos basada en libevent con un ligero cambio cooperativo de tareas implementado por greenlet.

Lo que obtienes es todo el rendimiento y la escalabilidad de un sistema de eventos con la elegancia y el modelo sencillo de bloqueo de la programación IO.

(no sé lo que el SO convención de responder a las preguntas realmente viejos es, pero decidí que aún añadiría mis 2 centavos)

Cuestiones relacionadas