pymp parallel python parallel-processing openmp

pymp - parallel python



OpenMP y Python (7)

Tengo experiencia en la codificación de OpenMP para máquinas de memoria compartida (tanto en C como en FORTRAN) para realizar tareas simples como la adición de matrices, la multiplicación, etc. (solo para ver cómo compite con LAPACK). Sé que OpenMP es suficiente para realizar tareas sencillas sin la necesidad de consultar la documentación.

Recientemente, cambié a Python para mis proyectos y no tengo ninguna experiencia con Python más allá de lo básico.

Mi pregunta es :

¿Cuál es la forma más fácil de usar OpenMP en Python? Por más fácil, me refiero al que requiere menos esfuerzo en el lado del programador (incluso si se trata de un gasto adicional del sistema).

La razón por la que uso OpenMP es porque un código de serie se puede convertir en un código paralelo de trabajo con unos pocos !$OMP s dispersos. El tiempo requerido para lograr una paralelización aproximada es fascinantemente pequeño. ¿Hay alguna forma de replicar esta característica en Python?

De navegar alrededor de SO, puedo encontrar:

  • Extensiones c
  • StackLess Python

Hay mas ¿Cuál se alinea mejor con mi pregunta?


Cython

Cython es compatible con OpenMP : con Cython, se puede agregar OpenMP usando el prange rango (rango paralelo) y agregando la directiva del compilador -fopenmp a setup.py.

Cuando se trabaja en una stanza de prange, la ejecución se realiza en paralelo porque deshabilitamos el bloqueo global del intérprete (GIL) mediante el uso de with nogil: para especificar el bloque en el que GIL está deshabilitado.

Para compilar _cython_np.pyx_ tenemos que modificar el script setup.py como se muestra a continuación. Le pedimos que informe al compilador de C para utilizar -fopenmp como argumento durante la compilación - para habilitar OpenMP y para enlazar con las bibliotecas de OpenMP.

Con el programa de Cython prange, podemos elegir diferentes enfoques de programación. Con la estática, la carga de trabajo se distribuye de manera uniforme entre las CPU disponibles. Sin embargo, como algunas de sus regiones de cálculo son costosas en el tiempo, mientras que otras son baratas, si le pedimos a Cython que programe los segmentos de trabajo utilizando la estática en todas las CPU, los resultados de algunas regiones se completarán más rápido que otros y esas hebras siéntate en reposo. Las opciones de programación dinámica y guiada intentan mitigar este problema asignando el trabajo en porciones más pequeñas dinámicamente en el tiempo de ejecución, de modo que las CPU se distribuyan de manera más uniforme cuando el tiempo de cálculo de la carga de trabajo es variable. Por lo tanto, para su código, la elección correcta variará según la naturaleza de su carga de trabajo.

Numba

La versión premium de Numba, NumbaPro, tiene soporte experimental de un operador de paralelización de prange para trabajar con OpenMP.

Pythran

Pythran (un compilador de Python a C ++ para un subconjunto de Python) puede aprovechar las posibilidades de vectorización y las posibilidades de paralelización basadas en OpenMP, aunque se ejecuta utilizando Python 2.7 solamente. Especifica secciones paralelas utilizando las directivas pragma omp (muy similar a la compatibilidad con OpenMP de Cython descrita anteriormente), por ejemplo:

PyPy

El compilador JIT Python PyPy es compatible con el módulo de multiprocesamiento (ver a continuación) y tiene un proyecto llamado PyPy-STM " una versión especial en desarrollo de PyPy que puede ejecutar múltiples subprocesos independientes y con hambre de CPU en el mismo proceso en paralelo ".

Nota al margen: multiprocesamiento

OpenMP es una interfaz de bajo nivel para múltiples núcleos. Es posible que desee mirar multiprocessing. El módulo de multiprocessing funciona a un nivel superior, compartiendo estructuras de datos de Python, mientras que OpenMP funciona con objetos primitivos C (por ejemplo, enteros y flotadores) una vez que haya compilado a C. Sólo tiene sentido usar OpenMP si está compilando su código ; Si no está compilando (p. ej., si está utilizando un código numpy eficiente y desea ejecutar en muchos núcleos), entonces seguir con el multiprocessing es probablemente el enfoque correcto.


Debido a GIL, no tiene sentido utilizar subprocesos para tareas intensivas de CPU en CPython. Necesita multiprocesamiento ( example ) o usar extensiones C que liberen GIL durante los cálculos, por ejemplo, algunas de las funciones numpy, por example .

Podrías escribir fácilmente extensiones C que usen múltiples hilos en Cython, por example .


Hay un paquete llamado pymp , que el autor lo describió como un paquete que trae funcionalidad de tipo OpenMP a Python. He intentado usarlo, pero con diferentes casos de uso: procesamiento de archivos. Funcionó. Creo que es bastante simple de usar. A continuación se muestra una muestra tomada de la página de GitHub:

import pymp ex_array = pymp.shared.array((100,), dtype=''uint8'') with pymp.Parallel(4) as p: for index in p.range(0, 100): ex_array[index] = 1 # The parallel print function takes care of asynchronous output. p.print(''Yay! {} done!''.format(index))


Que yo sepa, no hay un paquete OpenMP para Python (y no sé qué haría si hubiera uno). Si desea subprocesos directamente bajo su control, tendrá que utilizar una de las bibliotecas de subprocesos. Sin embargo, como han señalado otros, el GIL (Global Interpreter Lock) hace que el rendimiento de subprocesos múltiples en Python sea un poco ... bueno, sin sentido *. La GIL significa que solo un hilo puede acceder al intérprete a la vez.

Yo sugeriría mirar NumPy / SciPy en su lugar. NumPy le permite escribir código Matlab-esque donde está operando en matrices y matrices con operaciones simples. También tiene algunas capacidades de procesamiento paralelo, consulte la Wiki de SciPy .

Otros lugares para empezar a buscar:

* Ok, no tiene sentido, pero a menos que el tiempo se consuma fuera del código de Python (como por un proceso externo invocado a través de popen o algo así), los hilos no le van a comprar nada más que conveniencia.


Si quieres liberar GIL y usar OpenMP ypu puedes echar un vistazo a Cython. Ofrece un simple paralelismo para algunas tareas comunes. Puedes leer más en la documentation Cython.


Tal vez tu respuesta está en Cython:

"Cython admite el paralelismo nativo a través del módulo cython.parallel. Para usar este tipo de paralelismo, debe liberarse la GIL (consulte Liberar la GIL). Actualmente es compatible con OpenMP, pero más adelante es posible que se admita más backends". documentation


http://archive.euroscipy.org/talk/6857 "presenta las habilidades OpenMP de Cython centradas en bucles paralelos sobre matrices NumPy. Los ejemplos de código fuente demuestran cómo usar OpenMP de Python. Los resultados de los algoritmos paralelos con OpenMP muestran lo que pueden ser los aumentos de velocidad logrado para diferentes tamaños de datos en comparación con otras estrategias de paralelización ".

import numpy import cython from cython cimport parallel @cython.boundscheck(False) @cython.wraparound(False) def func(object[double, ndim=2] buf1 not None, object[double, ndim=2] buf2 not None, object[double, ndim=2] output=None, int num_threads=2): cdef unsigned int x, y, inner, outer if buf1.shape != buf2.shape: raise TypeError(''Arrays have different shapes: %s, %s'' % (buf1.shape, buf2.shape)) if output is None: output = numpy.empty_like(buf1) outer = buf1.shape[0] inner = buf1.shape[1] with nogil, cython.boundscheck(False), cython.wraparound(False): for x in parallel.prange(outer, schedule=''static'', num_threads=num_threads): for y in xrange(inner): output[x, y] = ((buf1[x, y] + buf2[x, y]) * 2 + buf1[x, y] * buf2[x, y]) return output