OpenMP et Python
j'ai de l'expérience dans le codage de OpenMP pour les machines à mémoire partagée (à la fois en C et en FORTRAN) pour effectuer des tâches simples comme l'ajout de matrice, la multiplication, etc. (Juste pour voir comment il rivalise avec LAPACK). Je connais suffisamment OpenMP pour effectuer des tâches simples sans avoir à consulter la documentation.
récemment, je suis passé à Python pour mes projets et je n'ai aucune expérience avec Python au-delà des bases absolues.
Ma question est :
qu'est-Ce que l' facile façon D'utiliser OpenMP en Python? Par plus facile, je veux dire celui qui demande le moins d'effort du côté du programmeur (même s'il vient au détriment du temps de système supplémentaire)?
La raison pour laquelle J'utilise OpenMP est qu'un code série peut être converti en un code parallèle fonctionnel avec quelques !$OMP
s éparpillés. Le temps requis pour atteindre un rugueuse la parallélisation est étonnamment petite. Est-il possible de reproduire cette fonctionnalité dans Python?
à Partir de parcourir DONC, je peux trouver:
- C extensions
- StackLess Python
existe-t-il? Laquelle correspond le mieux à ma question?
7 réponses
en raison de GIL, il n'y a pas de raison d'utiliser des threads pour les tâches intensives en CPython. Vous avez besoin de l'un ou l'autre multiprocesseur (exemple) ou utiliser des extensions C qui libèrent GIL pendant les calculs, par exemple, certaines fonctions de numpy,exemple.
vous pouvez facilement écrire des extensions C qui utilisent plusieurs threads dans Cython,exemple.
à ma connaissance, il n'y a pas de paquet OpenMP pour Python (et je ne sais pas ce que cela ferait s'il y en avait un). Si vous voulez des threads directement sous votre contrôle, vous devrez utiliser une des bibliothèques de threading. Cependant, comme d'autres l'ont souligné, le Gil (Global Interpreter Lock) rend le multi-threading en Python pour la performance un peu... eh bien, inutile*. La GIL signifie qu'un seul thread peut accéder à l'interpréteur à la fois.
je suggère de regarder au NumPy/SciPy à la place. NumPy vous permet d'écrire du code Matlab-esque où vous travaillez sur des tableaux et des matrices avec des opérations simples. Il a aussi des capacités de traitement en parallèle, voir le SciPy Wiki.
autres endroits pour commencer à chercher:
- Expériences de Prise en CPU des Tâches Beaucoup plus Rapidement
- accélérer Python (NumPy, Cython et Armure)
* Ok, ce n'est pas inutile, mais à moins que le temps ne soit consommé en dehors du code Python (comme par un processus externe invoqué via popen
ou un tel), les fils ne vont pas vous acheter autre chose que la commodité.
si vous voulez libérer GIL et utiliser OpenMP ypu peut jeter un oeil à Cython. Il offre un simple parallélisme pour certaines tâches communes. Vous pouvez lire plus à Cython documentation.
Peut-être que votre réponse est en Cython:
" Cython supporte le parallélisme natif à travers le cython.en parallèle du module. Pour utiliser ce type de parallélisme, la GIL doit être libérée (voir libération de la GIL). Il supporte actuellement OpenMP, mais plus tard d'autres backends pourraient être pris en charge." Cython Documentation
Cython
Cython a OpenMP support: avec Cython, OpenMP peut être ajouté en utilisant le prange
(gamme parallèle) et en ajoutant l'opérateur -fopenmp
directive compilateur à setup.py.
en travaillant dans une strophe prange, l'exécution est effectuée en parallèle parce que nous désactivons le global interprète de verrouillage (GIL) en utilisant with nogil:
pour spécifier le bloc où la GIL est désactivée.
Pour compiler _cython_np.pyx_ nous devons modifier le setup.py script comme montré ci-dessous. Nous lui demandons d'informer le compilateur C d'utiliser -fopenmp
comme argument lors de la compilation - pour activer OpenMP et créer un lien avec les bibliothèques OpenMP.
Avec Cython prange,
on peut choisir différentes approches de planification. statique, la charge de travail est répartie également entre les unités centrales disponibles. Toutefois, comme certaines de vos régions de calcul sont coûteuses en temps, tandis que d'autres sont bon marché - si nous demandons à Cython de programmer les morceaux de travail également en utilisant statique à travers les CPU, alors les résultats pour certaines régions se compléteront plus rapidement que d'autres et ces threads seront alors inactifs.
À la fois le dynamique et guidées options de calendrier tenter d'atténuer ce problème en répartissant le travail en petits morceaux de façon dynamique à l'exécution afin que les CPU soient répartis plus uniformément lorsque le temps de calcul de la charge de travail est variable. Ainsi, pour votre code, le bon choix varient selon la nature de votre charge de travail.
Numba
la version premium de Numba, NumbaPro, a le support expérimental d'un prange
opérateur de parallélisation pour travailler avec OpenMP.
Pythran
Pythran (un compilateur Python-to-C++ pour un sous-ensemble de Python) peut tirer parti des possibilités de vectorisation et des possibilités de parallélisation basées sur OpenMP, bien qu'il fonctionne en utilisant Python 2.7 seulement. Vous spécifiez des sections parallèles en utilisant pragma omp
directives (très similaire au support OpenMP de Cython décrit ci-dessus), par exemple:
PyPy
le compilateur PyPy de JIT Python supporte le module multiprocessing (voir ci-dessous) et a un projet appelé PyPy-STM"une version spéciale en développement de PyPy qui peut exécuter plusieurs threads indépendants et affamés de CPU dans le même processus en parallèlement".
note de Côté: multitraitement
OpenMP est une interface de bas niveau vers plusieurs noyaux. Vous pouvez regarder la multiprocessing.
multiprocessing
le module fonctionne à un niveau supérieur, partageant les structures de données Python, alors que OpenMP fonctionne avec les objets primitifs C (par exemple, entiers et flotteurs) une fois que vous avez compilé vers C. Il n'est logique d'utiliser OpenMP que si vous compilez votre code; si vous ne compilez pas (par exemple, si vous utilisez efficient numpy code et vous souhaitez exécuter sur de nombreux cœurs), puis coller avec multiprocessing
est probablement la bonne approche.
Il y a un paquet appelé pymp, que l'auteur décrit comme un paquet qui apporte des fonctionnalités de type OpenMP à Python. J'ai essayé de l'utiliser, mais avec les différents cas d'utilisation: traitement d'un fichier. Il a travaillé. Je pense que c'est assez simple à utiliser. Voici un exemple tiré de la page 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))
http://archive.euroscipy.org/talk/6857 "introduit les capacités OpenMP de Cython en se concentrant sur les boucles parallèles au-dessus des tableaux NumPy. Des exemples de code Source montrent comment utiliser OpenMP depuis Python. Les résultats pour les algorithmes parallèles avec OpenMP montrent quelles vitesses peuvent être obtenues pour différentes tailles de données par rapport à d'autres stratégies de parallélisation."
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