python - Greenlet vs. Trapos
concurrency gevent (3)
Esto es lo suficientemente interesante para analizar. Aquí hay un código para comparar el rendimiento de los puntos verdes versus el grupo de multiprocesamiento versus multi-threading:
import gevent
from gevent import socket as gsock
import socket as sock
from multiprocessing import Pool
from threading import Thread
from datetime import datetime
class IpGetter(Thread):
def __init__(self, domain):
Thread.__init__(self)
self.domain = domain
def run(self):
self.ip = sock.gethostbyname(self.domain)
if __name__ == "__main__":
URLS = [''www.google.com'', ''www.example.com'', ''www.python.org'', ''www.yahoo.com'', ''www.ubc.ca'', ''www.wikipedia.org'']
t1 = datetime.now()
jobs = [gevent.spawn(gsock.gethostbyname, url) for url in URLS]
gevent.joinall(jobs, timeout=2)
t2 = datetime.now()
print "Using gevent it took: %s" % (t2-t1).total_seconds()
print "-----------"
t1 = datetime.now()
pool = Pool(len(URLS))
results = pool.map(sock.gethostbyname, URLS)
t2 = datetime.now()
pool.close()
print "Using multiprocessing it took: %s" % (t2-t1).total_seconds()
print "-----------"
t1 = datetime.now()
threads = []
for url in URLS:
t = IpGetter(url)
t.start()
threads.append(t)
for t in threads:
t.join()
t2 = datetime.now()
print "Using multi-threading it took: %s" % (t2-t1).total_seconds()
aquí están los resultados:
Using gevent it took: 0.083758
-----------
Using multiprocessing it took: 0.023633
-----------
Using multi-threading it took: 0.008327
Creo que Greenlet afirma que no está obligado por GIL a diferencia de la biblioteca de subprocesos múltiples. Además, el doc de Greenlet dice que está destinado para operaciones de red. Para una operación intensiva de red, el cambio de hilo está bien y se puede ver que el enfoque de subprocesamiento múltiple es bastante rápido. También siempre es posible usar las bibliotecas oficiales de Python; Intenté instalar Greenlet en Windows y encontré un problema de dependencia de DLL, así que ejecuté esta prueba en una versión de Linux. Siempre intenta escribir un código con la esperanza de que se ejecute en cualquier máquina.
Soy nuevo en gevents y greenlets. Encontré una buena documentación sobre cómo trabajar con ellos, pero ninguno me dio una justificación sobre cómo y cuándo debería usar greenlets.
- ¿En qué son realmente buenos?
- ¿Es una buena idea usarlos en un servidor proxy o no?
- ¿Por qué no hilos?
De lo que no estoy seguro es de cómo pueden proporcionarnos simultaneidad si son básicamente correlpacidades.
Greenlets proporciona concurrencia pero no paralelismo. La concurrencia es cuando el código puede ejecutarse independientemente de otro código. Paralelismo es la ejecución simultánea de código concurrente. El paralelismo es particularmente útil cuando hay mucho trabajo por hacer en el espacio de usuario, y eso suele ser algo pesado en la CPU. La simultaneidad es útil para separar problemas, permitiendo programar diferentes partes y administrarlas más fácilmente en paralelo.
Greenlets realmente brilla en la programación de red donde las interacciones con un socket pueden ocurrir independientemente de las interacciones con otros sockets. Este es un ejemplo clásico de concurrencia. Debido a que cada greenlet se ejecuta en su propio contexto, puede continuar utilizando API síncronas sin enhebrar. Esto es bueno porque los hilos son muy caros en términos de memoria virtual y sobrecarga del núcleo, por lo que la concurrencia que puede lograr con los hilos es significativamente menor. Además, enhebrar en Python es más costoso y más limitado de lo habitual debido a GIL. Las alternativas a la concurrencia suelen ser proyectos como Twisted, libevent, libuv, node.js, etc., donde todo el código comparte el mismo contexto de ejecución y registra los controladores de eventos.
Es una idea excelente utilizar greenlets (con el soporte de red adecuado, como a través de gevent) para escribir un proxy, ya que el manejo de las solicitudes puede ejecutarse de manera independiente y debe escribirse como tal.
Greenlets proporciona concurrencia por las razones que di anteriormente. La concurrencia no es paralelismo. Al ocultar el registro de eventos y realizar la programación para usted en las llamadas que normalmente bloquearían el hilo actual, los proyectos como gevent exponen esta concurrencia sin requerir el cambio a una API asíncrona, y a un costo significativamente menor para su sistema.
- La concurrencia no es paralelismo
- Hilos vs. procesos
- Multiprocesamiento vs. hilos
- GIL vs. CPython
Tomando la respuesta de @ Max y agregando cierta relevancia para escalar, puede ver la diferencia. Lo logré cambiando las URL que se completarán de la siguiente manera:
URLS_base = [''www.google.com'', ''www.example.com'', ''www.python.org'', ''www.yahoo.com'', ''www.ubc.ca'', ''www.wikipedia.org'']
URLS = []
for _ in range(10000):
for url in URLS_base:
URLS.append(url)
Tuve que abandonar la versión de multiprocesamiento antes de que tuviera 500; pero en 10,000 iteraciones:
Using gevent it took: 3.756914
-----------
Using multi-threading it took: 15.797028
Entonces puedes ver que hay una diferencia significativa en E / S usando gevent