¿Qué demonios es gevent? (Parte 1 de 4)

Brian Salomaki
Lyft Engineering en Español
4 min readDec 5, 2022

Este artículo fue publicado originalmente el 14 de octubre de 2020 en eng.lyft.com por Roy Williams y fue traducido por Brian Salomaki.

Aspectos generales

gevent es un framework de multitarea cooperativa en python basado en corrutinas que hace uso de reemplazo dinámico (‘monkey patching’) para hacer que todo el código sea cooperativo. Gevent realmente viene del videojuego Eve Online que se implementó utilizando Stackless (una versión de Python que evita el uso de la pila de llamadas), el cual eventualmente se convirtió en eventlet que inspiró gevent. Al igual que Eve Online, gevent está lleno de misticismo y confunde a los forasteros.

Hay mucha complejidad en esa descripción, así que vamos a desglosarlo.

Corrutina

Las corrutinas dividen los programas en trabajo bloqueante y no bloqueante . Los desarrolladores de frontend están familiarizados con el infierno de usar retrollamadas (callback hell): cada una de esas retrollamadas es una corrutina.

doing some work
done first
done second

En el ejemplo anterior, las funciones son corrutinas — hacen algo de trabajo, llaman a una función bloqueante definiendo la retrollamada que indica las acciones a realizar cuando la función principal termina. Es importante destacar que las corrutinas tienen que ceder explícitamente el control para que se ejecute otra corrutina, lo que nos permite razonar fácilmente sobre dónde tenemos que preocuparnos por el intercalado (más sobre esto más adelante). ¡Las corrutinas no son hilos! Una corrutina también se conoce en gevent como un greenlet.

Multitarea cooperativa

La multitarea cooperativa es un método que se utiliza para permitir que una computadora maneje más trabajo concurrente de lo que permiten los recursos disponibles (por ejemplo, núcleos en su computadora). La multitarea cooperativa existe desde el inicio del tiempo compartido — Windows 3.1 dependía de multitarea cooperativa para permitir que varias aplicaciones se ejecutaran al mismo tiempo en una computadora con 1 núcleo. La desventaja principal, entonces y ahora, es que los sistemas cooperativos dependen de que las tareas… bien.. cooperen. En un sistema de multitarea apropiativa, como es el caso de los sistemas operativos modernos, el SO entiende las prioridades y cuánto tiempo se ha ejecutado cada tarea y puede interrumpir un proceso de larga ejecución para permitir que se ejecute otro. En un sistema cooperativo no existe un mecanismo así de planificación centralizada.

Reemplazo dinámico (Monkey Patching)

El reemplazo dinámico es una técnica para emparchar o modificar en tiempo de ejecución el comportamiento de una biblioteca estándar o de terceros. El reemplazo dinámico generalmente se considera una mala práctica, ya que puede introducir errores difíciles de entender y requiere que los parches se actualicen juntos con la biblioteca subyacente que se está parcheando. En el caso de un evento, el reemplazo dinámico tiene que ser absolutamente la primera cosa que hace un proceso; de lo contrario, las bibliotecas recibirán referencias a las implementaciones reales que son bloqueantes.

Should have slept 10 seconds

Conectando todo

A continuación tenemos un ejemplo completo usando gevent : primero emparchamos la biblioteca estándar que luego mágicamente hace que time.sleep sea cooperativo: en lugar de bloquear la CPU, cederá el control durante al menos el tiempo de suspensión. No se requirieron otros cambios en el código. gevent evita el infierno de las callbacks al emparchar la biblioteca estándar, automáticamente creando corrutinas — efectivamente permitiendo reanudar el trabajo desde el punto de cesión. Un corolario útil es cómo C# genera código con async/await: efectivamente parte la función cada vez que hay un await (que en inglés significa “espera”).

Ejecutaremos este código usando gevent.spawn para simular solicitudes concurrentes.

0: Doing first step
0: Doing second step
1: Doing first step
1: Doing second step
0: Doing third step
1: Doing third step

Estas corrutinas son cooperativas: observa que nunca vemos que se ejecute nada más entre first step y second step porque nunca se cedió el control.

Gevent — las partes buenas

gevent no es pura complejidad innecesaria. Las corrutinas son sustancialmente más ligeras que los hilos o procesos; podemos ejecutar decenas de miles de greenlets en un servidor que podría ejecutar sólo cientos de hilos. gevent funciona con casi todas las bibliotecas de terceros sin cambios de código. En cambio, twisted, tornado y asyncio requieren el uso de bibliotecas que se adapten bien a sus bucles de eventos para cualquier bloqueo de E/S; en contraste, gevent trabaja con requests sin necesidad de configuración adicional. gevent promete: “agregue estas dos líneas de código a su proyecto y obtendrás un rendimiento mágicamente más alto,” situación que en la mayoría de veces se cumple.

Problemas con gevent

Desafortunadamente, no todo es miel sobre hojuelas con gevent. gevent puede conducir a problemas reales en donde el resultado final no sea correcto, ya que se intercalan bloques de código en forma inesperada. Si una biblioteca utiliza código nativo, podemos seguir enfrentando bloqueos. Por último, aunque gevent optimiza el código para aumentar el rendimiento, puede conducir a verdaderos problemas de latencia.

Pero esta publicación ya se está volviendo bastante larga, por lo que en la siguiente parte hablaremos de los problemas en donde el resultado no es correcto y cómo evitarlos. En la parte 3 se verán los problemas de capacidad de respuesta.

Si quieres jugar con este código tú mismo, ¡puedes descargarlo (en inglés) como un Jupyter Notebook !

Esto es parte de una serie de 4 partes. Te sugerimos que también consultes la Parte 2: Corrección , la Parte 3: Rendimiento y la Parte 4: Aplicar los aprendizajes para brindar valor a los usuarios .

Lyft se compromete a mejorar la vida de la gente al ofrecerles los mejores medios de transporte en el mundo.

--

--