Maison >développement back-end >Tutoriel Python >Un guide du multiprocessement Python et de la programmation parallèle
Accélérer les calculs est un objectif que tout le monde veut atteindre. Et si vous avez un script qui pourrait fonctionner dix fois plus vite que sa durée actuelle? Dans cet article, nous examinerons le multiprocessement Python et une bibliothèque appelée multiprocessement. Nous allons parler de ce qu'est le multiprocessement, de ses avantages et de la façon d'améliorer le temps d'exécution de vos programmes Python en utilisant la programmation parallèle.
d'accord, alors allons-y!
Avant de plonger dans le code Python, nous devons parler de l'informatique parallèle, qui est un concept important en informatique.
Habituellement, lorsque vous exécutez un script Python, votre code devient à un moment donné un processus et le processus s'exécute sur un seul noyau de votre CPU. Mais les ordinateurs modernes ont plus d'un noyau, alors que se passe-t-il si vous pouviez utiliser plus de cœurs pour vos calculs? Il s'avère que vos calculs seront plus rapides.
Prenons cela comme un principe général pour l'instant, mais plus tard, dans cet article, nous verrons que ce n'est pas universellement vrai.
sans entrer dans trop de détails, l'idée derrière le parallélisme est d'écrire votre code de telle manière qu'il peut utiliser plusieurs cœurs du CPU.
pour faciliter les choses, regardons un exemple.
Imaginez que vous avez un énorme problème à résoudre, et vous êtes seul. Vous devez calculer la racine carrée de huit nombres différents. Que fais-tu? Eh bien, vous n'avez pas beaucoup d'options. Vous commencez par le premier numéro et vous calculez le résultat. Ensuite, vous continuez avec les autres.
Et si vous avez trois amis en mathématiques prêts à vous aider? Chacun d'eux calculera la racine carrée de deux nombres, et votre travail sera plus facile car la charge de travail est répartie également entre vos amis. Cela signifie que votre problème sera résolu plus rapidement.
D'accord, donc tout est clair? Dans ces exemples, chaque ami représente un noyau du CPU. Dans le premier exemple, toute la tâche est résolu séquentiellement par vous. C'est ce qu'on appelle l'informatique en série. Dans le deuxième exemple, puisque vous travaillez avec quatre cœurs au total, vous utilisez l'informatique parallèle. L'informatique parallèle implique l'utilisation de processus parallèles ou de processus divisés entre plusieurs cœurs dans un processeur.
Nous avons établi ce qu'est la programmation parallèle, mais comment l'utiliser? Eh bien, nous avons déjà dit que l'informatique parallèle implique l'exécution de plusieurs tâches entre plusieurs cœurs du processeur, ce qui signifie que ces tâches sont exécutées simultanément. Il y a quelques questions que vous devriez considérer avant d'approcher la parallélisation. Par exemple, y a-t-il d'autres optimisations qui pourraient accélérer nos calculs?
Pour l'instant, prenons pour acquis que la parallélisation est la meilleure solution pour vous. Il existe principalement trois modèles en informatique parallèle:
Dans cet article, nous illustrons le premier modèle, qui est également le plus simple.
Une façon d'atteindre le parallélisme dans Python est d'utiliser le module multiprocesseur. Le module de multiprocessement vous permet de créer plusieurs processus, chacun avec son propre interprète Python. Pour cette raison, le multiprocessement Python accomplit le parallélisme basé sur les processus.
Vous avez peut-être entendu parler d'autres bibliothèques, comme le filetage, qui est également intégré à Python, mais il existe des différences cruciales entre elles. Le module de multiprocessement crée de nouveaux processus, tandis que le threading crée de nouveaux threads.
Dans la section suivante, nous examinerons les avantages de l'utilisation du multiprocessement.
Voici quelques avantages du multiprocessement:
Le premier avantage est lié aux performances. Étant donné que le multiprocessement crée de nouveaux processus, vous pouvez faire mieux l'utilisation de la puissance de calcul de votre CPU en divisant vos tâches parmi les autres noyaux. La plupart des processeurs sont des processeurs multicœurs de nos jours, et si vous optimisez votre code, vous pouvez gagner du temps en résolvant les calculs en parallèle.
Le deuxième avantage examine une alternative au multitraitement, qui est le multithreading. Les threads ne sont cependant pas des processus, et cela a ses conséquences. Si vous créez un fil, il est dangereux de le tuer ou même de l'interrompre comme vous le feriez avec un processus normal. Étant donné que la comparaison entre le multiprocessement et le multithreading n'est pas dans le cadre de cet article, je vous encourage à faire une lecture supplémentaire à ce sujet.
Le troisième avantage du multiprocessement est qu'il est assez facile à mettre en œuvre, étant donné que la tâche que vous essayez de gérer est adaptée à la programmation parallèle.
Nous sommes enfin prêts à écrire du code python!
Nous allons commencer par un exemple très basique et nous l'utiliserons pour illustrer les aspects principaux du multiprocessement Python. Dans cet exemple, nous aurons deux processus:
Nous allons utiliser le processus enfant pour exécuter une certaine fonction. De cette façon, le parent peut continuer son exécution.
Voici le code que nous utiliserons pour cet exemple:
<span>from multiprocessing import Process </span> <span>def bubble_sort(array): </span> check <span>= True </span> <span>while check == True: </span> check <span>= False </span> <span>for i in range(0, len(array)-1): </span> <span>if array[i] > array[i+1]: </span> check <span>= True </span> temp <span>= array[i] </span> array<span>[i] = array[i+1] </span> array<span>[i+1] = temp </span> <span>print("Array sorted: ", array) </span> <span>if __name__ == '__main__': </span> p <span>= Process(target=bubble_sort, args=([1,9,4,5,2,6,8,4],)) </span> p<span>.start() </span> p<span>.join() </span>
Dans cet extrait, nous avons défini une fonction appelée bubble_sort (array). Cette fonction est une implémentation vraiment naïve de l'algorithme de tri de tri de bulles. Si vous ne savez pas ce que c'est, ne vous inquiétez pas, car ce n'est pas si important. La chose cruciale à savoir est que c'est une fonction qui fait un peu de travail.
À partir du multiprocessement, nous importons le processus de classe. Cette classe représente une activité qui sera exécutée dans un processus distinct. En effet, vous pouvez voir que nous avons passé quelques arguments:
Une fois que nous avons créé une instance pour la classe de processus, nous devons seulement démarrer le processus. Cela se fait en écrivant p.start (). À ce stade, le processus est démarré.
Avant de quitter, nous devons attendre que le processus de l'enfant termine ses calculs. La méthode join () attend que le processus se termine.
Dans cet exemple, nous n'avons créé qu'un seul processus enfant. Comme vous pouvez le deviner, nous pouvons créer plus de processus enfants en créant plus d'instances dans la classe de processus.
Et si nous devons créer plusieurs processus pour gérer plus de tâches à forte intensité de processeur? Avons-nous toujours besoin de commencer et d'attendre explicitement la résiliation? La solution ici est d'utiliser la classe de piscine.
La classe de pool vous permet de créer un pool de processus de travail, et dans l'exemple suivant, nous examinerons comment pouvons-nous l'utiliser. Ceci est notre nouvel exemple:
<span>from multiprocessing import Process </span> <span>def bubble_sort(array): </span> check <span>= True </span> <span>while check == True: </span> check <span>= False </span> <span>for i in range(0, len(array)-1): </span> <span>if array[i] > array[i+1]: </span> check <span>= True </span> temp <span>= array[i] </span> array<span>[i] = array[i+1] </span> array<span>[i+1] = temp </span> <span>print("Array sorted: ", array) </span> <span>if __name__ == '__main__': </span> p <span>= Process(target=bubble_sort, args=([1,9,4,5,2,6,8,4],)) </span> p<span>.start() </span> p<span>.join() </span>
Dans cet extrait de code, nous avons une fonction cube (x) qui prend simplement un entier et renvoie sa racine carrée. Facile, non?
Ensuite, nous créons une instance de la classe de pool, sans spécifier aucun attribut. La classe de pool crée par défaut un processus par noyau CPU. Ensuite, nous exécutons la méthode de la carte avec quelques arguments.
La méthode MAP applique la fonction du cube à chaque élément de l'itérable que nous fournissons - qui, dans ce cas, est une liste de chaque nombre de 10 à N.
L'énorme avantage de ceci est que les calculs sur la liste sont effectués en parallèle!
Créer plusieurs processus et faire des calculs parallèles n'est pas nécessairement plus efficace que l'informatique en série. Pour les tâches faibles à forte intensité de processeur, le calcul en série est plus rapide que le calcul parallèle. Pour cette raison, il est important de comprendre quand vous devez utiliser le multiprocessement - ce qui dépend des tâches que vous effectuez.
pour vous convaincre de cela, regardons un exemple simple:
<span>from multiprocessing import Pool </span><span>import time </span><span>import math </span> N <span>= 5000000 </span> <span>def cube(x): </span> <span>return math.sqrt(x) </span> <span>if __name__ == "__main__": </span> <span>with Pool() as pool: </span> result <span>= pool.map(cube, range(10,N)) </span> <span>print("Program finished!") </span>
Cet extrait est basé sur l'exemple précédent. Nous résolvons le même problème, qui calcule la racine carrée de n nombres, mais de deux manières. Le premier implique l'utilisation du multiprocessement Python, tandis que le second ne le fait pas. Nous utilisons la méthode perf_counter () de la bibliothèque temporelle pour mesurer les performances de temps.
Sur mon ordinateur portable, j'obtiens ce résultat:
<span>from multiprocessing import Pool </span><span>import time </span><span>import math </span> N <span>= 5000000 </span> <span>def cube(x): </span> <span>return math.sqrt(x) </span> <span>if __name__ == "__main__": </span> <span># first way, using multiprocessing </span> start_time <span>= time.perf_counter() </span> <span>with Pool() as pool: </span> result <span>= pool.map(cube, range(10,N)) </span> finish_time <span>= time.perf_counter() </span> <span>print("Program finished in {} seconds - using multiprocessing".format(finish_time-start_time)) </span> <span>print("---") </span> <span># second way, serial computation </span> start_time <span>= time.perf_counter() </span> result <span>= [] </span> <span>for x in range(10,N): </span> result<span>.append(cube(x)) </span> finish_time <span>= time.perf_counter() </span> <span>print("Program finished in {} seconds".format(finish_time-start_time)) </span>
Comme vous pouvez le voir, il y a plus d'une deuxième différence. Donc, dans ce cas, le multiprocessement est meilleur.
Changeons quelque chose dans le code, comme la valeur de N. Laissez-le à n = 10000 et voyons ce qui se passe.
C'est ce que j'obtiens maintenant:
<span>> python code.py </span>Program finished <span>in 1.6385094 seconds - using multiprocessing </span>--- Program finished <span>in 2.7373942999999996 seconds </span>
Que s'est-il passé? Il semble que le multiprocessement soit désormais un mauvais choix. Pourquoi?
La surcharge introduite en divisant les calculs entre les processus est trop par rapport à la tâche résolue. Vous pouvez voir quelle différence il y a en termes de performances de temps.
Dans cet article, nous avons parlé de l'optimisation des performances du code Python en utilisant le multiprocessement Python.
Tout d'abord, nous avons brièvement introduit ce qu'est le calcul parallèle et les principaux modèles pour l'utiliser. Ensuite, nous avons commencé à parler du multiprocessement et de ses avantages. En fin de compte, nous avons vu que la parallélisation des calculs n'est pas toujours le meilleur choix et que le module de multiprocessement devrait être utilisé pour paralléliser les tâches liées au processeur. Comme toujours, il s'agit de considérer le problème spécifique auquel vous êtes confronté et d'évaluer les avantages et les inconvénients des différentes solutions.
J'espère que vous avez trouvé l'apprentissage du multiprocessement Python aussi utile que moi.
Le principal avantage de l'utilisation du multiprocessement dans Python est qu'il permet l'exécution de plusieurs processus simultanément. Cela est particulièrement bénéfique lors de la travail avec des tâches à forte intensité de processeur, car il permet au programme d'utiliser plusieurs noyaux du CPU, améliorant ainsi considérablement la vitesse et l'efficacité du programme. Contrairement au threading, le multiprocessement ne souffre pas du verrouillage mondial de l'interprète (GIL) dans Python, ce qui signifie que chaque processus peut s'exécuter indépendamment sans être affecté par d'autres processus. Cela fait du multiprocessement un outil puissant pour la programmation parallèle dans Python.
Quelle est la différence entre le multiprocessement et le multithreading dans Python?
Le partage des données entre les processus dans Python peut être obtenu en utilisant les mécanismes de mémoire partagés du module multiprocesseur. Il s'agit notamment des classes de valeur et de tableau, qui permettent la création de variables et de tableaux partagés respectivement. Cependant, il est important de noter que, parce que chaque processus a son propre espace mémoire, les modifications apportées aux variables ou aux tableaux partagées dans un processus ne se refléteront pas dans d'autres processus, sauf s'ils sont explicitement synchronisés à l'aide de verrous ou d'autres primitives de synchronisation fournies par le module multiprocesseur.
tout en multiprocesseur dans Python Peut considérablement améliorer la vitesse et l'efficacité de votre programme, il est également livré avec son propre ensemble de défis. L'un des principaux pièges est la complexité accrue de votre code. La gestion de plusieurs processus peut être plus complexe que la gestion d'un programme unique, en particulier lorsqu'il s'agit de gérer les données partagées et de synchroniser les processus. De plus, la création d'un nouveau processus est plus à forte intensité de ressources que la création d'un nouveau thread, ce qui peut conduire à une utilisation accrue de la mémoire. Enfin, toutes les tâches ne conviennent pas à la parallélisation, et dans certains cas, les frais généraux de création et de gestion de plusieurs processus peuvent l'emporter sur les gains de performance potentiels.
Gestion des exceptions en multiprocessement dans Python peut être un peu délicate, car les exceptions qui se produisent dans les processus enfants ne se propagent pas automatiquement au processus parent. Cependant, le module de multiprocessement fournit plusieurs façons de gérer les exceptions. Une façon consiste à utiliser la méthode is_alive () de la classe de processus pour vérifier si un processus est toujours en cours d'exécution. Si la méthode renvoie fausse, cela signifie que le processus s'est terminé, ce qui pourrait être dû à une exception. Une autre façon consiste à utiliser l'attribut EXITCODE de la classe de processus, qui peut fournir plus d'informations sur les raisons pour lesquelles un processus terminé.
Oui, vous pouvez utiliser le multiprocessement avec le multiprocessement avec Autres bibliothèques Python. Cependant, il est important de noter que toutes les bibliothèques ne sont pas conçues pour être utilisées dans un environnement multiprocesseur. Certaines bibliothèques peuvent ne pas être en filetage ou ne pas prendre en charge l'exécution simultanée. Par conséquent, c'est toujours une bonne idée de vérifier la documentation de la bibliothèque que vous utilisez pour voir si elle prend en charge le multiprocessement.
Le débogage d'un programme multiprocesseur dans Python peut être difficile, car les outils de débogage traditionnels peuvent ne pas fonctionner comme prévu dans un environnement multiprocesseur. Cependant, il existe plusieurs techniques que vous pouvez utiliser pour déboguer votre programme. Une façon consiste à utiliser des instructions d'impression ou une journalisation pour suivre l'exécution de votre programme. Une autre façon consiste à utiliser la fonction SET_TRACE () du module PDB pour définir des points d'arrêt dans votre code. Vous pouvez également utiliser des outils de débogage spécialisés qui prennent en charge le multiprocessement, tels que la fonction log_to_stderr () du module multiprocesseur, qui vous permet de enregistrer l'activité de vos processus à l'erreur standard.
Oui, vous pouvez utiliser le multiprocessement dans Python sur différents systèmes d'exploitation. Le module de multiprocessement fait partie de la bibliothèque Python standard, ce qui signifie qu'il est disponible sur toutes les plates-formes qui prennent en charge Python. Cependant, le comportement du module de multiprocessement peut varier légèrement entre différents systèmes d'exploitation en raison de différences dans la façon dont ils gèrent les processus. Par conséquent, c'est toujours une bonne idée de tester votre programme sur le système d'exploitation cible pour s'assurer qu'il fonctionne comme prévu.
- Utilisez la classe de pool pour gérer votre travailleur Les processus, car il fournit une interface de niveau supérieur qui simplifie le processus de création et de gestion des processus.
- Nettoyez toujours vos processus en appelant la méthode join () de la classe de processus, qui garantit que le processus s'est terminé avant que le programme ne se poursuive .
- Gérer correctement les exceptions pour empêcher votre programme de s'écraser de façon inattendue.
- Testez soigneusement votre programme pour vous assurer qu'il fonctionne correctement dans un environnement multiprocesseur.
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!