2010-06-25 19 views
5

He decidido aprender cómo se hace el multi-threading en Python, e hice una comparación para ver qué tipo de ganancia de rendimiento obtendría en una CPU de doble núcleo. Descubrí que mi código simple multiproceso realmente funciona más lento que el equivalente secuencial, y no puedo entender por qué.Enlazado de Python inesperadamente más lento

La prueba me las ingenié era generar una larga lista de números al azar y luego imprimir la máxima

from random import random 
import threading 

def ox(): 
    print max([random() for x in xrange(20000000)]) 

ox() dura aproximadamente 6 segundos para completar en mi Intel Core 2 Duo, mientras ox();ox() toma unos 12 segundos.

Intenté llamar a ox() desde dos hilos para ver qué tan rápido se completaba.

def go(): 
    r = threading.Thread(target=ox) 
    r.start() 
    ox() 

go() toma alrededor de 18 segundos para completar, con los dos resultados de impresión dentro de 1 segundo de unos de otros. ¿Por qué debería ser más lento?

Sospecho que ox() se paraleliza automáticamente, porque si miro la pestaña de rendimiento del administrador de tareas de Windows y llamo al ox() en mi consola de python, ambos procesadores alcanzan aproximadamente el 75% de utilización hasta que finaliza. ¿Python automáticamente paraleliza cosas como max() cuando puede?

Respuesta

9
  1. Python tiene el GIL. Python bytecode solo será ejecutado por un solo procesador a la vez. Solo ciertos módulos C (que no administran el estado de Python) podrán ejecutarse simultáneamente.
  2. El Python GIL tiene una gran sobrecarga al bloquear el estado entre subprocesos. Existen soluciones para esto en las versiones más nuevas o en las ramas de desarrollo, que al menos deberían hacer que el código multi-threaded de la CPU sea tan rápido como el código de un solo subproceso.

Debe utilizar un marco de proceso múltiple para paralelizar con Python. Afortunadamente, el módulo multiprocessing que se envía con Python lo hace bastante fácil.

Muy pocos idiomas pueden auto-paralelizar expresiones. Si esa es la funcionalidad que desea, sugiero Haskell (Data Parallel Haskell)

+5

Vale la pena señalar que el enhebrado sigue siendo útil en Python para ciertos tipos de tareas, como las operaciones vinculadas a E/S. –

1

El problema está en la función random() Si elimina al azar de su código. Ambos núcleos intentan acceder al estado compartido de la función aleatoria. Los núcleos funcionan consecuentemente y pasan mucho tiempo en la sincronización de cachés. Tal comportamiento se conoce como uso compartido falso. Lee este artículo False Sharing