Python est [GIL (Global Interpolator Lock)](https://ja.wikipedia.org/wiki/%E3%82%B0%E3%83%AD%E3%83%BC%E3%83%90%E3% 83% AB% E3% 82% A4% E3% 83% B3% E3% 82% BF% E3% 83% 97% E3% 83% AA% E3% 82% BF% E3% 83% AD% E3% 83% 83% E3% 82% AF) est appliqué et, fondamentalement, si vous avez plusieurs cœurs de processeur, vous ne pouvez pas utiliser toutes les ressources simplement en écrivant le code.
Cependant, lors du traitement d'une grande quantité de données, vous souhaitez parfois utiliser toutes les ressources CPU de la machine pour calculer le plus rapidement possible.
Avec des mots clés tels que Traitement parallèle Python Si vous effectuez une recherche, vous pouvez souvent voir l'explication de module multiprocesseur par la bibliothèque standard, donc je pense que beaucoup de gens l'utilisent. ..
Je voudrais utiliser ce module lors de la création d'un système qui intègre un traitement parallèle, mais honnêtement, c'est un peu gênant lors de l'écriture de code abandonné ...
Par conséquent, je voudrais présenter un module appelé Joblib qui peut exécuter le traitement parallèle plus facilement et plus rapidement.
Sans parler de la quantité réduite de code, comme autre avantage
--Il affiche également l'erreur générée par le processus enfant.
Etc. Tous me sont très utiles car je dois les implémenter moi-même en multitraitement.
Le premier est l'installation. C'est un coup avec pip. La version au moment de la rédaction de cet article est la 0.9.3.
pip install joblib
Successfully installed joblib-0.9.3
L'environnement utilisé pour le test est un MacBook Pro avec 4 cœurs virtuels et 2 cœurs physiques.
Pour comparer simplement les temps de calcul, testez avec un code comme celui-ci. Le contenu du calcul lui-même n'a pas de signification particulière.
Tout d'abord, répétez un calcul simple, mesurez le temps de calcul avec le module de temps et affichez-le.
# -*- coding: utf-8 -*-
from time import time
def process(n):
return sum([i*n for i in range(100000)])
start = time()
#Calcul itératif
total = 0
for i in range(10000):
total += process(i)
print(total)
print('{}Ça a pris une seconde'.format(time() - start))
249972500250000000
78.Cela a pris 2647480965 secondes
La réponse au calcul est 249972500250000000, ce qui prend 78 secondes.
Modifions uniquement la partie calcul itérative du code ci-dessus et parallélisons-la. La parallélisation multiprocessus peut être obtenue en combinant Parallèle et différé.
# -*- coding: utf-8 -*-
from joblib import Parallel, delayed
from time import time
def process(n):
return sum([i*n for i in range(100000)])
start = time()
#Calcul itératif(Parallélisation)
r = Parallel(n_jobs=-1)( [delayed(process)(i) for i in range(10000)] )
print(sum(r))
print('{}Ça a pris une seconde'.format(time() - start))
249972500250000000
37.5521140099 a pris
Il a été raccourci à 37 secondes! La réponse au calcul est également correcte. J'ai pu raccourcir rapidement le temps de calcul simplement en réécrivant une partie du code.
L'argument parallèle n_jobs est le nombre de cœurs à utiliser, et si vous définissez ceci sur -1, il s'exécutera toujours avec le nombre maximum de cœurs pouvant être utilisés.
Si vous le définissez sur 1, ce sera la même chose que l'exécution sans parallélisation, il est donc facile de le restaurer. Il semble qu'il n'y ait pas de problème même si le processus itératif est essentiellement écrit en parallèle.
De plus, si vous spécifiez une valeur numérique comprise entre 0 et 10 dans l'argument détaillé, la progression sera sortie en fonction de la fréquence spécifiée. (0 signifie pas de sortie, 10 est le plus fréquent)
r = Parallel(n_jobs=-1, verbose=10)( [delayed(process)(i) for i in range(10000)] )
Dans l'exemple de code ci-dessus, il est possible de faire référence à une variable qui existe dans une étendue externe à partir de la méthode de processus qui est exécutée en parallèle, mais il n'est pas possible d'attribuer une nouvelle valeur. En effet, la zone de mémoire qui peut être référencée diffère pour chaque processus.
Le code suivant fonctionne normalement, mais le code parallélisé provoque une erreur et ne peut pas être exécuté.
#Référencer et manipuler le numéro de variable externe à partir de la méthode de processus
number = 0
def process(n):
number = 3.14
return sum([i*n for i in range(100000)])
Pour résoudre ce problème, il est nécessaire de créer une variable qui partage une zone de mémoire entre les processus. Il est fourni dans le module multitraitement, alors utilisons-le.
Le code ci-dessus peut être réalisé comme suit.
# -*- coding: utf-8 -*-
from joblib import Parallel, delayed
from multiprocessing import Value, Array
shared_int = Value('i', 1)
def process(n):
shared_int.value = 3.14
return sum([i*n for i in range(100000)])
#Calcul itératif(Parallélisation)
Parallel(n_jobs=-1)( [delayed(process)(i) for i in range(10000)] )
print(shared_int.value)
3.14
Vous pouvez utiliser la classe Value pour préparer des nombres tels que int et double en tant que variables partagées. Veuillez noter qu'il est nécessaire de spécifier le type avec le premier argument à l'avance.
Il est également possible de préparer une liste de types spécifiés en utilisant ʻArray ('d', [0.0, 0.0, 0.0]) `.
Cela semble utile lorsque vous souhaitez afficher votre propre progression personnalisée!
J'ai été surpris de pouvoir l'implémenter en douceur lorsque j'ai essayé le traitement parallèle avec Python.
L'auteur publie chaque jour diverses informations techniques sur Twitter. Je vous serais reconnaissant si vous pouviez me suivre.
https://twitter.com/YuhsakInoue
Recommended Posts