[Python] Traitement parallèle facile avec Joblib

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.

Installation

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.

Code utilisé pour les tests

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.

Paralléliser avec Joblib

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)] )

Bonus: manipuler des variables en dehors de la méthode

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!

finalement

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

[Python] Traitement parallèle facile avec Joblib
Traitement parallèle Python (multitraitement et Joblib)
Exécution parallèle facile avec le sous-processus python
Traitez facilement des images en Python avec Pillow
Traitement d'image avec Python
Traitement parallèle avec multitraitement
Comment faire un traitement parallèle multicœur avec python
Traitement parallèle sans signification profonde en Python
Traitement d'image avec Python (partie 2)
100 coups de traitement du langage avec Python 2015
Traitement parallèle avec des fonctions locales
"Traitement Apple" avec OpenCV3 + Python3
[Analyse de co-occurrence] Analyse de co-occurrence facile avec Python! [Python]
Traitement du signal acoustique avec Python (2)
Traitement du signal acoustique avec Python
Synchronisation facile des dossiers avec Python
Traitement parallèle avec Parallel de scikit-learn
Traitement d'image avec Python (partie 1)
Traitement d'image avec Python (3)
Compilation facile de Python avec NUITKA-Utilities
Serveur HTTP facile avec Python
[Python] Traitement d'image avec scicit-image
Introduction au traitement parallèle distribué Python par Ray
100 traitements de langage avec Python
100 traitements de langage avec Python (chapitre 3)
Traitement d'image avec la binarisation Python 100 knocks # 3
Programmation facile Python + OpenCV avec Canopy
Transmission de courrier facile avec Hâte Python3
Optimisation bayésienne très simple avec Python
Résumé de l'exemple de code de traitement parallèle / parallèle Python
Lire des fichiers en parallèle avec Python
Visualisez facilement vos données avec Python seaborn.
100 traitement d'image par Python Knock # 2 Échelle de gris
Bases du traitement d'images binarisées par Python
Traitement d'image par Python 100 knock # 10 filtre médian
Extraction de mots-clés facile avec TermExtract pour Python
[Python] Test super facile avec instruction assert
[Python] Vérification simple du type d'argument avec la classe de données
100 traitement d'image avec Python Knock # 8 Max Pooling
Effectuez périodiquement un traitement arbitraire avec Python Twisted
Laissez Heroku faire le traitement en arrière-plan avec Python
Introduction facile de la reconnaissance vocale avec Python
100 traitements de langage avec Python (chapitre 2, partie 2)
Traitement d'image avec Python et OpenCV [Tone Curve]
3. Traitement du langage naturel par Python 2-1. Réseau de co-occurrence
Traitement d'image par Python 100 knock # 12 motion filter
3. Traitement du langage naturel par Python 1-1. Word N-gram
[Easy Python] Lecture de fichiers Excel avec openpyxl
100 traitements de langage avec Python (chapitre 2, partie 1)
Application Web facile avec Python + Flask + Heroku
Dessin avec Matrix-Reinventor of Python Image Processing-
Traitement d'image avec Python 100 knocks # 7 pooling moyen
[Easy Python] Lecture de fichiers Excel avec des pandas
Scraping Web facile avec Python et Ruby
[Python] Essayez facilement l'apprentissage amélioré (DQN) avec Keras-RL
Traitement d'image léger avec Python x OpenCV
Traitement d'image par Python 100 knock # 9 Filtre Gaussien
FizzBuzz en Python3
Grattage avec Python
Python est facile