performance - ¿Qué hace una diferencia significativa de rendimiento entre eventlet y gevent?
wsgi asyncsocket (2)
Bueno, gevent no está "mayormente" escrito en Cython, aunque algunas secciones críticas sí lo están.
Cython hace una gran diferencia. Las optimizaciones del procesador funcionan mucho mejor con el código compilado. La predicción de ramificación, por ejemplo, se desintegra en los sistemas basados en VM porque la dirección indirecta de la ramificación en un nivel de ejecución de VM es opaca a ella. La huella del caché es más estricta. El código compilado hace una gran diferencia aquí, e IO puede ser muy sensible a la latencia.
En una vena similar, libev es muy rápido. Las mismas razones.
No parece que eventlet debería haber estado utilizando el concentrador de selección (Python 2.6 por lo general tiene como valor predeterminado epoll). Sin embargo, si se quedara bloqueado en la selección, eso lo haría realmente lento (porque Python tiene que convertir el fd_set selecto de ida y vuelta a una lista de Python, por lo que se pone feo cuando está en medio de un bucle).
No he hecho ningún perfil, pero estaría dispuesto a apostar a que libev / libevent plus Cython hace la gran diferencia. Notablemente, algunas de las primitivas de enhebrado están en Cython en gevent. Este es un gran problema porque muchos códigos los tocan indirectamente a través de IO e incluso la biblioteca estándar en algunos puntos.
En cuanto a la capa de emulación adicional de eventlet, parece que hay mucho más rebote. En gevent, la ruta del código parece construir devoluciones de llamada y dejar que el concentrador las llame. eventlet parece hacer más de la contabilidad que el centro está haciendo en gevent. Una vez más, sin embargo, no lo he perfilado. En cuanto a la simulación del mono, se ven bastante similares.
El servidor WSGI es otro difícil. Notablemente, el análisis del encabezado en gevent se difiere a la biblioteca estándar, mientras que ellos mismos lo implementan en eventlet. No estoy seguro de si esto es un gran impacto o no, pero no sería sorprendente si hubiera algo acechando allí. Lo más revelador es que el servidor de eventlet está basado en una versión de la biblioteca estándar BaseHTTPServer. No puedo imaginar que esto sea muy óptimo. Gevent implementa un servidor que es consciente de la emulación.
Esas dos bibliotecas comparten la filosofía similar y las decisiones de diseño similares como resultado. Pero este popular punto de referencia WSGI dice que eventlet
es mucho más lento que gevent
. ¿Qué hace que su rendimiento sea tan diferente?
Como sé, las principales diferencias entre ellos son:
gevent
depende intencionalmente de y está acoplado alibevent
(libevent
, anteriormente),eventlet
define una interfaz de reactor independiente e implementa adaptadores particulares que utilizanselect
,epoll
y Twisted reactor detrás de él. ¿La interfaz adicional del reactor hace golpes de rendimiento crítico?gevent
se escribe principalmente en Cython, mientras que eleventlet
está escrito en Python puro. ¿Es Cython compilado de forma nativa más rápido que Python puro, para los programas no muy computacionales pero enlazados a IO?Las primitivas de
gevent
emulan las interfaces de las bibliotecas estándar, mientras que las primitivas deeventlet
difieren de las estándar y proporcionan una capa adicional para emularlas. ¿La capa de emulación adicional hace que eleventlet
sea más lento?¿La implementación de
eventlet.wsgi
es peor quegevent.pywsgi
?
Realmente me pregunto, porque en general se ven muy similares para mí.
Lo siento por la respuesta tardía.
Hay dos razones principales de la gran diferencia de rendimiento en ese punto de referencia :
- Como se dijo antes, las rutas críticas de Gevent están fuertemente optimizadas
- Ese punto de referencia hace pruebas de estrés. Ya no está enlazado a IO, porque intenta hacer que la máquina ejecute tantas solicitudes como sea posible. Y ahí es donde brilla el código citonizado.
"En el mundo real" eso solo ocurre durante las "slashdot" ráfagas de tráfico. Lo que es importante y uno debería estar listo, pero cuando sucede, reacciona agregando más servidores o desactivando las funciones de recursos pesados. No he visto un punto de referencia que en realidad agregue más servidores cuando aumenta la carga.
Si, por otro lado, el punto de referencia simularía una carga de "día normal" (que variaría de un sitio web a otro), pero en general podría aproximarse a la solicitud, pausa aleatoria, repetición. Cuanto menos se detenga, más tráfico estaremos simulando. También el lado del cliente del benchmark debería simular la latencia. En Linux, esto se podría hacer usando un increíble netem [1], de lo contrario, colocando pequeños retrasos antes de las llamadas de respuesta / envío (lo que sería muy difícil porque los puntos de referencia usualmente utilizan bibliotecas de nivel superior).
Ahora, si se cumplen esas condiciones, en realidad evaluaríamos los problemas del límite de IO. Pero los resultados no serían demasiado impresionantes: todos los candidatos sirvieron con éxito cargas de 10, 50 e incluso 200 qps. Aburrido, ¿verdad? Así que podríamos medir la distribución de la latencia, el tiempo para atender las solicitudes del 99%, etc. Gevent todavía mostraría mejores resultados. Pero la diferencia difícilmente sería impresionante.