¿Por qué el multiprocesamiento usa solo un solo núcleo después de importar numpy?

No estoy seguro de si esto cuenta más como un problema de sistema operativo, pero pensé que preguntaría aquí en caso de que alguien tenga alguna idea del final de Python.

He estado intentando paralelizar un CPU for bucle usando joblib , pero encuentro que en lugar de que cada proceso de trabajo se asigne a un núcleo diferente, termino con todos ellos asignados al mismo núcleo y sin ganancia de rendimiento.

Aquí hay un ejemplo muy trivial …

 from joblib import Parallel,delayed import numpy as np def testfunc(data): # some very boneheaded CPU work for nn in xrange(1000): for ii in data[0,:]: for jj in data[1,:]: ii*jj def run(niter=10): data = (np.random.randn(2,100) for ii in xrange(niter)) pool = Parallel(n_jobs=-1,verbose=1,pre_dispatch='all') results = pool(delayed(testfunc)(dd) for dd in data) if __name__ == '__main__': run() 

… y esto es lo que veo en htop mientras se ejecuta este script:

htop

Estoy ejecutando Ubuntu 12.10 (3.5.0-26) en una computadora portátil con 4 núcleos. Claramente, joblib.Parallel está generando procesos separados para los diferentes trabajadores, pero ¿hay alguna manera de hacer que estos procesos se ejecuten en diferentes núcleos?

Después de un poco más de googlear encontré la respuesta aquí .

Resulta que ciertos módulos de Python ( numpy , scipy , tables , pandas , skimage …) se skimage con la afinidad del núcleo en la importación. Por lo que puedo decir, este problema parece deberse específicamente a que se vinculan con bibliotecas de OpenBLAS multiproceso.

Una solución es restablecer la afinidad de la tarea usando

 os.system("taskset -p 0xff %d" % os.getpid()) 

Con esta línea pegada después de las importaciones del módulo, mi ejemplo ahora se ejecuta en todos los núcleos:

htop_workaround

Mi experiencia hasta ahora ha sido que esto no parece tener ningún efecto negativo en el numpy de numpy , aunque esto probablemente sea específico de la máquina y la tarea.

Actualizar:

También hay dos formas de deshabilitar el comportamiento de restablecimiento de la afinidad de la CPU de OpenBLAS. En tiempo de ejecución, puede utilizar la variable de entorno OPENBLAS_MAIN_FREE (o GOTOBLAS_MAIN_FREE ), por ejemplo

 OPENBLAS_MAIN_FREE=1 python myscript.py 

O alternativamente, si está comstackndo OpenBLAS desde la fuente, puede deshabilitarlo permanentemente en tiempo de comstackción editando la Makefile.rule para contener la línea

 NO_AFFINITY=1 

Python 3 ahora expone los métodos para establecer directamente la afinidad

 >>> import os >>> os.sched_getaffinity(0) {0, 1, 2, 3} >>> os.sched_setaffinity(0, {1, 3}) >>> os.sched_getaffinity(0) {1, 3} >>> x = {i for i in range(10)} >>> x {0, 1, 2, 3, 4, 5, 6, 7, 8, 9} >>> os.sched_setaffinity(0, x) >>> os.sched_getaffinity(0) {0, 1, 2, 3} 

Esto parece ser un problema común con Python en Ubuntu, y no es específico de joblib :

  • Tanto multiprocessing.map como joblib usan solo 1 cpu después de la actualización de Ubuntu 10.10 a 12.04
  • El multiprocesamiento de Python utiliza solo un núcleo
  • Procesamiento multiprocesamiento.Pool bloqueado en un solo núcleo

Sugeriría experimentar con la afinidad de la CPU (conjunto de taskset ).