7

Estaba desarrollando una aplicación en gae usando python 2.7, una llamada ajax solicita algunos datos de una API, una sola solicitud podría tomar ~ 200 ms, sin embargo, cuando abro dos navegadores y hago dos las solicitudes en un momento muy cercano toman más del doble de eso, intenté poner todo en hilos pero no funcionó ... (esto sucede cuando la aplicación está en línea, no solo en el servidor dev)Paralelismo en python no funciona bien

Así que escribí esta sencilla prueba para ver si esto es un problema en pitón en general (en el caso de una espera de ocupado), aquí está el código y el resultado:

def work(): 
    t = datetime.now() 
    print threading.currentThread(), t 
    i = 0 
    while i < 100000000: 
     i+=1 
    t2 = datetime.now() 
    print threading.currentThread(), t2, t2-t 

if __name__ == '__main__': 
    print "single threaded:" 
    t1 = threading.Thread(target=work) 
    t1.start() 
    t1.join() 

    print "multi threaded:" 
    t1 = threading.Thread(target=work) 
    t1.start() 
    t2 = threading.Thread(target=work) 
    t2.start() 
    t1.join() 
    t2.join() 

el resultado en Mac OS X, do ore i7 (4 núcleos, 8 hilos), python2.7:

single threaded: 
<Thread(Thread-1, started 4315942912)> 2011-12-06 15:38:07.763146 
<Thread(Thread-1, started 4315942912)> 2011-12-06 15:38:13.091614 0:00:05.328468 

multi threaded: 
<Thread(Thread-2, started 4315942912)> 2011-12-06 15:38:13.091952 
<Thread(Thread-3, started 4323282944)> 2011-12-06 15:38:13.102250 
<Thread(Thread-3, started 4323282944)> 2011-12-06 15:38:29.221050 0:00:16.118800 
<Thread(Thread-2, started 4315942912)> 2011-12-06 15:38:29.237512 0:00:16.145560 

Esto es bastante impactante !! si un solo hilo tomaría 5 segundos para hacer esto ... pensé que iniciar dos hilos al mismo tiempo tomaría el mismo tiempo para terminar ambas tareas, pero lleva casi el triple de tiempo ... esto hace que toda la idea de enhebrar sea inútil, como ¡sería más rápido hacerlos secuencialmente!

lo que me estoy perdiendo aquí ..

+3

¿Has leído algo sobre Global Interpreter Lock (GIL) en Python? Si desea un procesamiento paralelo, debe considerar el multiprocesamiento, no el enhebrado. La ejecución está limitada a un único hilo a la vez a menos que las bibliotecas con las que está trabajando estén diseñadas específicamente para liberar el GIL. –

+2

Su punto de referencia está mal diseñado.Su caso de uso real estará vinculado a IO, no a CPU. Python's GIL se comporta de manera bastante diferente en cada caso. Enhebrar * debería * funcionar bien para usted en su caso de uso real. – zeekay

+1

@ g.d.d.c. el multiprocesamiento no está disponible dentro de GAE – bpgergo

Respuesta

9

David Beazley gave a talk sobre este tema en PyCon 2010. Como ya se ha indicado, para algunas tareas, el uso de subprocesos especialmente con varios núcleos puede conducir a un rendimiento más lento que la misma tarea realizada por un solo hilo. El problema, Beazley encontró, tuvo que ver con múltiples núcleos que tienen un "GIL battle":

enter image description here

Para evitar la contención GIL, se pueden obtener mejores resultados que tienen las tareas se ejecutan en procesos separados en lugar de hilos separados. El módulo multiprocessing proporciona una forma conveniente de hacerlo, especialmente dado que la API de multiprocesamiento es muy similar a la API de subprocesamiento.

import multiprocessing as mp 
import datetime as dt 
def work(): 
    t = dt.datetime.now() 
    print mp.current_process().name, t 
    i = 0 
    while i < 100000000: 
     i+=1 
    t2 = dt.datetime.now() 
    print mp.current_process().name, t2, t2-t 

if __name__ == '__main__': 
    print "single process:" 
    t1 = mp.Process(target=work) 
    t1.start() 
    t1.join() 

    print "multi process:" 
    t1 = mp.Process(target=work) 
    t1.start() 
    t2 = mp.Process(target=work) 
    t2.start() 
    t1.join() 
    t2.join() 

produce

single process: 
Process-1 2011-12-06 12:34:20.611526 
Process-1 2011-12-06 12:34:28.494831 0:00:07.883305 
multi process: 
Process-3 2011-12-06 12:34:28.497895 
Process-2 2011-12-06 12:34:28.503433 
Process-2 2011-12-06 12:34:36.458354 0:00:07.954921 
Process-3 2011-12-06 12:34:36.546656 0:00:08.048761 

PS. Como señaló Zeekay en los comentarios, la batalla de GIL es solo severa para las tareas vinculadas a la CPU. No debería ser un problema para tareas vinculadas a IO.

+0

¿Este comportamiento es específico de Python? Y si es así, ¿por qué? –

+1

El GIL es específico de Python, por lo que las "batallas de GIL" son específicas del GIL. No estoy seguro de que algo similar pueda suceder en otros idiomas. – unutbu

1

me gustaría ver dónde va el tiempo. Supongamos, por ejemplo, que el servidor solo puede responder una consulta cada 200 ms. Entonces no hay nada que puedas hacer, solo recibirás una respuesta cada 200ms porque eso es todo lo que el servidor puede darte.

+0

Mira su código. Él está llamando 'datetime', sin comunicarse con un servidor. –

Cuestiones relacionadas