Hace (mucho tiempo) escribí una araña web que multiprocedí para permitir que se produjeran solicitudes concurrentes al mismo tiempo. Eso fue en mi juventud de Python, en los días antes de que supiera sobre el GIL y los problemas asociados que crea para el código multiproceso (IE, ¡la mayoría de las veces las cosas terminan en serie!) ...
Me gustaría volver a trabajar este código para hacerlo más robusto y tener un mejor rendimiento. Básicamente, podría hacer esto de dos maneras: podría usar el nuevo módulo de multiprocesamiento en 2.6+ o podría optar por un modelo basado en un reactor / evento de algún tipo. Prefiero hacerlo más tarde, ya que es mucho más simple y menos propenso a errores.
Entonces, la pregunta se refiere a qué marco sería el más adecuado para mis necesidades. La siguiente es una lista de las opciones que conozco hasta ahora:
- Twisted : El abuelo de los marcos de reactores Python: parece complejo y un poco hinchado Curva de aprendizaje empinada para una tarea pequeña.
- Eventlet : De los chicos de lindenlab . Marco basado en Greenlet orientado a este tipo de tareas. Sin embargo, eché un vistazo al código y no es demasiado bonito: no cumple con pep8, está disperso con impresiones (¿por qué la gente hace esto en un marco?), API parece un poco inconsistente.
- PyEv : Inmaduro, parece que nadie lo está usando en este momento, aunque está basado en liberant, por lo que tiene un backend sólido.
- asyncore : De stdlib: über de bajo nivel, parece mucho trabajo de campo involucrado solo para sacar algo del suelo.
- tornado : Aunque este es un producto orientado al servidor diseñado para servidores de sitios web dinámicos, presenta un cliente HTTP asíncrono y un simple ioloop . Parece que podría hacer el trabajo pero no para lo que estaba destinado. [editar: desafortunadamente no se ejecuta en Windows, lo cual lo cuenta para mí, es un requisito para mí admitir esta plataforma aburrida]
¿Hay algo que me haya perdido? ¡Seguramente debe haber una biblioteca por ahí que se ajuste al punto óptimo de una biblioteca de red asincrónica simplificada!
[edit: muchas gracias a intgr por su puntero a esta página . Si se desplaza hacia abajo, verá que hay una lista muy buena de proyectos que tienen como objetivo abordar esta tarea de una forma u otra. En realidad, parece que las cosas han avanzado desde el inicio de Twisted: las personas ahora parecen favorecer una solución basada en la co-rutina en lugar de una solución tradicional orientada al reactor / devolución de llamada. Los beneficios de este enfoque son un código más directo más claro: ciertamente lo he encontrado en el pasado, especialmente cuando trabajo con boost.asioen C ++, ese código basado en la devolución de llamada puede conducir a diseños que pueden ser difíciles de seguir y son relativamente oscuros para el ojo inexperto. El uso de co-rutinas le permite escribir código que parece un poco más sincrónico al menos. ¡Supongo que ahora mi tarea es averiguar cuál de estas bibliotecas me gusta y probarla! Me alegro de haber preguntado ahora ...]
[editar: tal vez sea de interés para cualquiera que haya seguido o tropezado con esta pregunta o que se preocupe por este tema en algún sentido: encontré una excelente reseña del estado actual de las herramientas disponibles para este trabajo]
select
para la multiplexación de E / S. Pero debería poder obtener un rendimiento decente con tornado-pyuv . 2. Ahora hay asyncio en Python 3.3+ y su backport trollius que permite ejecutar cualquier aplicación Tornado en su bucle de eventos (Twisted será compatible pronto).Respuestas:
Me gustó el módulo Python de concurrencia que se basa en microthreads Stackless Python o Greenlets para un enhebrado liviano. Todas las E / S de red de bloqueo se hacen asíncronas de forma transparente a través de un solo
libevent
bucle, por lo que deberían ser casi tan eficientes como un servidor asíncrono real.Supongo que es similar a Eventlet de esta manera.
La desventaja es que su API es bastante diferente de los módulos
sockets
/ de Pythonthreading
; necesita reescribir un poco de su aplicación (o escribir una capa de compatibilidad de compatibilidad)Editar: Parece que también hay cogen , que es similar, pero utiliza los generadores mejorados de Python 2.5 para sus corutinas, en lugar de Greenlets. Esto lo hace más portátil que la concurrencia y otras alternativas. La E / S de red se realiza directamente con epoll / kqueue / iocp.
fuente
Twisted es complejo, tienes razón en eso. Twisted no está hinchado.
Si echas un vistazo aquí: http://twistedmatrix.com/trac/browser/trunk/twisted encontrarás un conjunto organizado, completo y muy bien probado de muchos protocolos de Internet, así como un código auxiliar para escribir e implementar aplicaciones de red muy sofisticadas. No confundiría hinchazón con amplitud.
Es bien sabido que la documentación de Twisted no es la más fácil de usar a primera vista, y creo que esto rechaza a un número desafortunado de personas. Pero Twisted es increíble (en mi humilde opinión) si pones el tiempo. Lo hice y demostró que valió la pena, y recomendaría a otros que prueben lo mismo.
fuente
gevent es eventlet limpiado .
En cuanto a API, sigue las mismas convenciones que la biblioteca estándar (en particular, módulos de subprocesamiento y multiprocesamiento) donde tiene sentido. Entonces tiene cosas familiares como Cola y Evento para trabajar.
Solo admite libevent ( actualización: libev desde 1.0 ) como implementación del reactor, pero lo aprovecha al máximo, presentando un servidor WSGI rápido basado en libevent-http y resolviendo consultas DNS a través de libevent-dns en lugar de usar un grupo de subprocesos como la mayoría de las otras bibliotecas hacer. ( actualización: dado que 1.0 c-ares se usa para hacer consultas DNS asíncronas; threadpool también es una opción).
Al igual que eventlet, hace que las devoluciones de llamada y los aplazamientos sean innecesarios mediante el uso de greenlets .
Vea los ejemplos: descarga simultánea de múltiples URL , webchat de sondeo largo .
fuente
Nicholas Piël compiló una comparación realmente interesante de tales marcos en su blog: ¡vale la pena leerlo!
fuente
Ninguna de estas soluciones evitará el hecho de que el GIL previene el paralelismo de la CPU: son solo mejores formas de obtener el paralelismo IO que ya tiene con los subprocesos. Si crees que puedes mejorar IO, busca uno de estos, pero si tu cuello de botella está en el procesamiento de los resultados, nada aquí ayudará, excepto el módulo de multiprocesamiento.
fuente
No iría tan lejos como para llamar a Twisted hinchado, pero es difícil entenderlo. Evité realmente establecerme en un aprendizaje durante bastante tiempo ya que siempre quise algo un poco más fácil para 'pequeñas tareas'.
Sin embargo, ahora que he trabajado un poco más, debo decir que tener todas las baterías incluidas es MUY agradable.
Todas las otras bibliotecas asíncronas con las que he trabajado terminan siendo mucho menos maduras de lo que parecen. El bucle de eventos de Twisted es sólido.
No estoy muy seguro de cómo resolver la curva de aprendizaje Twisted empinada. Podría ayudar si alguien lo bifurca y limpia algunas cosas, como eliminar todos los problemas de compatibilidad hacia atrás y los proyectos muertos. Pero esa es la naturaleza del software maduro, supongo.
fuente
PortableGtkReactor
?Kamaelia no ha sido mencionada todavía. Su modelo de concurrencia se basa en el cableado de componentes con mensajes que pasan entre las bandejas de entrada y las de salida. Aquí hay una breve descripción general.
fuente
Empecé a usar retorcido para algunas cosas. La belleza de esto es casi porque está "hinchada". Hay conectores para casi cualquiera de los protocolos principales que existen. Puede tener un robot jabber que tomará comandos y los publicará en un servidor IRC, se los enviará por correo electrónico a alguien, ejecutará un comando, leerá desde un servidor NNTP y supervisará los cambios en una página web. La mala noticia es que puede hacer todo eso y puede hacer que las cosas sean demasiado complejas para tareas simples como lo explicó el OP. Sin embargo, la ventaja de Python es que solo incluye lo que necesita. Entonces, aunque la descarga puede ser de 20 MB, solo puede incluir 2 MB de bibliotecas (que todavía es mucho). Mi mayor queja con Twisted es que, aunque incluyen ejemplos, cualquier cosa más allá de un servidor tcp básico está solo.
Aunque no es una solución de Python, últimamente he visto que node.js ganaba mucha más tracción. De hecho, he considerado buscarlo para proyectos más pequeños, pero me estremezco cuando escucho javascript :)
fuente
Hay un buen libro sobre el tema: "Twisted Network Programming Essentials", de Abe Fettig. Los ejemplos muestran cómo escribir código muy pitónico y, personalmente, no me parecen basados en un marco hinchado. Mire las soluciones en el libro, si no están limpias, entonces no sé qué significa limpio.
Mi único enigma es el mismo que tengo con otros marcos, como Ruby. Me preocupa, ¿se amplía? Odiaría comprometer a un cliente a un marco que tendrá problemas de escalabilidad.
fuente
Whizzer es un pequeño marco de socket asíncrono que utiliza pyev. Es muy rápido, principalmente debido a pyev. Intenta proporcionar una interfaz similar como retorcida con algunos pequeños cambios.
fuente
Prueba también Syncless . Está basado en la rutina (por lo que es similar a Concurrence, Eventlet y gevent). Implementa reemplazos sin bloqueo para socket.socket, socket.gethostbyname (etc.), ssl.SSLSocket, time.sleep y select.select. Es rápido. Necesita Stackless Python y libevent. Contiene una extensión obligatoria de Python escrita en C (Pyrex / Cython).
fuente
Confirmo la bondad de syncless . Puede usar libev (la versión más nueva, limpia y de mejor rendimiento de libevent). Algunas veces, no tiene tanto apoyo como libevent, pero ahora el proceso de desarrollo va más allá y es muy útil.
fuente
Si solo desea una biblioteca de solicitudes HTTP simplificada y liviana, entonces encuentro que Unirest es realmente bueno
fuente
Le invitamos a echar un vistazo a PyWorks, que adopta un enfoque bastante diferente. Permite que las instancias de objetos se ejecuten en su propio hilo y realiza llamadas de función a ese objeto de forma asíncrona.
Simplemente deje que una clase herede de Task en lugar de objeto y es asíncrona, todas las llamadas a métodos son Proxies. Los valores de retorno (si los necesita) son proxies futuros.
PyWorks se puede encontrar en http://bitbucket.org/raindog/pyworks
fuente