Skip to content

Instantly share code, notes, and snippets.

@copitux
Created April 8, 2013 07:53
Show Gist options
  • Save copitux/5335010 to your computer and use it in GitHub Desktop.
Save copitux/5335010 to your computer and use it in GitHub Desktop.
[Spanish] High concurrency. Ando jugando con estas tecnologías y los conceptos pueden estar equivocados. Fork y corrige si ves algo raro sin dudarlo!

High concurrency

threading, multiprocessing, eventloop, coroutines, celery, twisted, gevent, libevent, eventlet, libev, epoll, select, kqueue, greenlet ...

Aquí el fin último es la asincronia, no bloquear la aplicación/ejecución y para ello nos apoyamos en la concurrencia y paralelismo. También conocido como asyncronous I/O

En aplicaciones web donde networking I/O está a la orden del día, sumado a alto rendimiento (x000 request/sec) soluciones como gevent se hacen necesarias.

Clasics

threading => Hilos de python, no demasiado eficientes debido al GIL

multiprocessing => Pues creamos multiproceso con la API del multihilo, no demasiado eficiente para aplicaciones web de alta concurrencia

Event loop => Hacemos uso de sockets no bloqueantes (para networking I/O operations) y delegamos al sistema operativo la creación y gestión de los mismos

Event loop

Nos apoyamos en las herramientas que proporciona el sistema operativo (unix: epoll, select, freebsd: kqueue ...) que se encargan de la carga real de asincronia en operaciones I/O, así como la notificación de eventos

iloop conocido como el bucle infinito encargado de escuchar dichos eventos y lanzar los callbacks asociados a cada tarea asyncrona creada.

Uno de las librerias encargadas de esta gestión es libevent o libev, ambas usadas por gevent en sus versiones 0.13.8 y 1.0dev respectivamente.

Otra libreria, más bien framework, es Twisted.

Twisted = iloop + callbacks

El código es escrito de forma asyncrona, y debes pensar de forma asyncrona.

Lo que aumenta la complejidad del código, al tratar con los Deferreds (Promesas) y el iloop directamente.

El código es esplicitamente asyncrono, el programador desarrolla el callback que será llamado cuando el evento sea procesado. Entra en juego la parte de python que puede considerarse como programación funcional.

Ey Twisted, voy a llamar 5 veces a la API de Zendesk. Ya si eso cuando acabes me ejecutas "este_callback_de_notificacion" que yo le voy contando al usuario que esta en camino la creación de los tickets, que le aviso por correo cuando acaben.


Pero claro, complejidad en el código no gusta. Si no necesitas de toda la infraestructura del framework de Twisted para networking / protocolos quizá sea mejor otra opción

Oye, y si pudiera programar de forma syncrona pero que se ejecute de forma asyncrona?

Welcome gevent magic

Gevent = iloop + coroutines

Rápidamente explicadas las coroutines son funciones que pueden suspender su ejecución y continuar la misma más tarde

En el core de python tenemos los generators formados con yield que cumplen esta premisa

Sin embargo gevent hace uso de greenlet, una librería python-C que implementa las coroutines con más control en la ejecución y una API más sencilla

from greenlet import greenlet

def test1():
    print 12
    gr2.switch()
    print 34

def test2():
    print 56
    gr1.switch()
    print 78

gr1 = greenlet(test1)
gr2 = greenlet(test2)
gr1.switch()

# > 12 56 34

La magía de gevent llega cuando tu como developer no interactuas con el iloop, lo hace gevent por tí behind the scenes cuando en tu código cliente haces uso de operaciones networking I/O.

Un flujo sencillo (Ha dicho sencillo?=??) sería así:

  1. Tengo la función alarm_to_ticket que realiza 3 cosas:
  • Ask catalogue if alarm exists
  • Ask diagnosis_system if need diagnosis
  • Send ticket to zendesk
  1. Wrapeo mi funcion con utils de gevent, que hacen uso de greenlets que convierten mi función en suspendable
  2. Entra en runtime
  3. La llamada se suspende y se resumen cuando delegue las operaciones de networking a gevent

Podría entenderse como callback en la siguiente ejecución/línea

Y como consigue gevent la asincronia?, monkey-patcheando la librería socket del core de python. Ala!

from gevent import monkey; monkey.patch_socket()
import urllib2 # it's usable from multiple greenlets now

Oculta el layer de asincronía (y su complejidad) dejando al developer cliente con código falsamente síncrono, en teoría más legible y sencillo.

y llego Celery y dijo aquí mi fusil aquí...

Celery: Deja, ya me encargo yo de lidiar con estas herramientas. Me da igual cual eh? Soporto threading, multiprocessing, eventlet y tengo en desarrollo gevent. Tu usa la API que te proporciono de programación funcional simple y olvidate

Celery hace uso de sistemas de paso de mensajes soportando diferentes transports/brokers (RabbitMQ, Redis, SQLAlchemy, the Django Database, MongoDB, Amazon SQS, CouchDB, Beanstalk) mientras hablen AMPQ. De dicha conexión se hace cargo la librería kombu

Celery utiliza workers creados por los diferentes backends de concurrencia antes comentados que se encargaran de ejecutar las tasks creadas por el developer cliente

Celery utiliza layers de serialización para pasar dichas tasks al sistema de paso de mensajes. Desde pickle con Python hasta json, yaml... para otros lenguajes

Pega estas 3 capas y tienes el 50% de Celery: Coder > Task > Serialize > Send message <> Broker capture and send to worker > worker execute.

Ey! y la otra dirección?

Celery puede hacer uso de backends de resultados de dichas tareas (lo que por supuesto es un gasto de recursos) para que el coder sepa de forma asyncrona que ha retornado la task. Soporta varios backends como redis, rabbitMQ, MongoDB ...

Cuando uno cree que ya esta bien con Celery, llega y te cuenta

Psé; tengo un sistema de colas y enrutamiento. Puedes crearte unos workers gestionados con eventlet y otros con multiprocessing y a traves de colas y enrutamiento mandar ciertas tasks a unos y a otros, que no todas las tasks van a poder ser gestionadas por un sistema de eventos.

A esto súmale:

  1. Una API inmensamnete colorida, limpia y flexible
  2. Monitorizar las tasks
  3. Scheduling
  4. Webhooks
  5. Integración con frameworks (Django a la perfección) ...

Suena todo increible, la vida real no será tan placentera. La asincronía y concurrencia añade complejidad al sistema, si además soportamos paralelismo real más todavía

Debemos estar seguros de necesitarlo


Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment