Dans notre précédent tutoriel, nous avons appris sur l’Exemple CSV Python. Dans ce tutoriel, nous allons apprendre le Multiprocessing en Python avec des exemples.
Multiprocessing en Python
Le traitement parallèle attire de plus en plus l’attention de nos jours. Si vous ne savez toujours pas ce qu’est le traitement parallèle, apprenez-en plus sur Wikipedia. Alors que les fabricants de CPU continuent d’ajouter de plus en plus de cœurs à leurs processeurs, créer du code parallèle est un excellent moyen d’améliorer les performances. Python a introduit le module multiprocessing pour nous permettre d’écrire du code parallèle. Pour comprendre la principale motivation de ce module, nous devons connaître quelques bases de la programmation parallèle. Après avoir lu cet article, nous espérons que vous serez en mesure de rassembler des connaissances sur ce sujet.
Multiprocessing en Python : Processus, File d’attente et Verrous
Il existe de nombreuses classes dans le module de multiprocessing de Python pour construire un programme parallèle. Parmi elles, trois classes de base sont Process
, Queue
et Lock
. Ces classes vous aideront à construire un programme parallèle. Mais avant de décrire celles-ci, commençons par un code simple. Pour rendre un programme parallèle utile, vous devez connaître le nombre de cœurs dans votre ordinateur. Le module Multiprocessing de Python vous permet de le savoir. Le code simple suivant affichera le nombre de cœurs dans votre ordinateur.
import multiprocessing
print("Number of cpu : ", multiprocessing.cpu_count())
La sortie suivante peut varier pour votre ordinateur. Pour moi, le nombre de cœurs est de 8.
Classe Process de multiprocessing de Python
La classe Process
de multiprocessing en Python est une abstraction qui configure un autre processus Python, lui fournit du code à exécuter et un moyen pour l’application parente de contrôler l’exécution. Il existe deux fonctions importantes appartenant à la classe Process – les fonctions start()
et join()
. Tout d’abord, nous devons écrire une fonction qui sera exécutée par le processus. Ensuite, nous devons instancier un objet de processus. Si nous créons un objet de processus, rien ne se passera tant que nous ne lui dirons pas de commencer le traitement via la fonction start()
. Ensuite, le processus s’exécutera et renverra son résultat. Ensuite, nous indiquons au processus de se terminer via la fonction join()
. Sans l’appel de la fonction join()
, le processus restera inactif et ne se terminera pas. Donc, si vous créez de nombreux processus et ne les terminez pas, vous pourriez rencontrer une pénurie de ressources. Ensuite, vous devrez peut-être les tuer manuellement. Une chose importante est que si vous souhaitez transmettre des arguments à travers le processus, vous devez utiliser l’argument de mot-clé args
. Le code suivant sera utile pour comprendre l’utilisation de la classe Process.
from multiprocessing import Process
def print_func(continent='Asia'):
print('The name of continent is : ', continent)
if __name__ == "__main__": # confirms that the code is under main function
names = ['America', 'Europe', 'Africa']
procs = []
proc = Process(target=print_func) # instantiating without any argument
procs.append(proc)
proc.start()
# instanciation du processus avec des arguments
for name in names:
# print(name)
proc = Process(target=print_func, args=(name,))
procs.append(proc)
proc.start()
# compléter les processus
for proc in procs:
proc.join()
La sortie du code suivant sera:
Classe Python multiprocessing Queue
Vous avez des connaissances de base sur les structures de données informatiques, vous connaissez probablement la file d’attente. Les modules de multiprocessus Python fournissent une classe Queue
qui est exactement une structure de données premier entré, premier sorti (FIFO). Ils peuvent stocker n’importe quel objet Python pickle (bien que les objets simples soient préférables) et sont extrêmement utiles pour partager des données entre les processus. Les files d’attente sont particulièrement utiles lorsqu’elles sont passées en tant que paramètre à la fonction cible d’un processus pour permettre au processus de consommer des données. En utilisant la fonction put()
, nous pouvons insérer des données dans la file d’attente, et en utilisant get()
, nous pouvons obtenir des éléments des files d’attente. Voici un exemple rapide de code.
from multiprocessing import Queue
colors = ['red', 'green', 'blue', 'black']
cnt = 1
# instanciation d'un objet file d'attente
queue = Queue()
print('pushing items to queue:')
for color in colors:
print('item no: ', cnt, ' ', color)
queue.put(color)
cnt += 1
print('\npopping items from queue:')
cnt = 0
while not queue.empty():
print('item no: ', cnt, ' ', queue.get())
cnt += 1
Python multiprocessing Lock Class
La tâche de la classe Lock est assez simple. Elle permet au code de revendiquer un verrou afin qu’aucun autre processus ne puisse exécuter un code similaire tant que le verrou n’a pas été libéré. Ainsi, la tâche de la classe Lock est principalement de deux types. L’un est de revendiquer le verrou et l’autre est de le libérer. Pour revendiquer le verrou, la fonction acquire()
est utilisée et pour libérer le verrou, la fonction release()
est utilisée.
Exemple de multiprocessus Python
Dans cet exemple de multiprocessing en Python, nous allons fusionner toutes nos connaissances ensemble. Supposons que nous avons quelques tâches à accomplir. Pour réaliser cette tâche, nous utiliserons plusieurs processus. Nous allons donc maintenir deux files d’attente. L’une contiendra les tâches et l’autre contiendra le journal des tâches terminées. Ensuite, nous instancions les processus pour accomplir la tâche. Notez que la classe Queue de Python est déjà synchronisée. Cela signifie que nous n’avons pas besoin d’utiliser la classe Lock pour bloquer l’accès de plusieurs processus au même objet file d’attente. C’est pourquoi nous n’avons pas besoin d’utiliser la classe Lock dans ce cas. Voici l’implémentation où nous ajoutons des tâches à la file d’attente, puis créons des processus et les démarrons, puis utilisons join()
pour terminer les processus. Enfin, nous imprimons le journal à partir de la deuxième file d’attente.
from multiprocessing import Lock, Process, Queue, current_process
import time
import queue # imported for using queue.Empty exception
def do_job(tasks_to_accomplish, tasks_that_are_done):
while True:
try:
'''
try to get task from the queue. get_nowait() function will
raise queue.Empty exception if the queue is empty.
queue(False) function would do the same task also.
'''
task = tasks_to_accomplish.get_nowait()
except queue.Empty:
break
else:
'''
if no exception has been raised, add the task completion
message to task_that_are_done queue
'''
print(task)
tasks_that_are_done.put(task + ' is done by ' + current_process().name)
time.sleep(.5)
return True
def main():
number_of_task = 10
number_of_processes = 4
tasks_to_accomplish = Queue()
tasks_that_are_done = Queue()
processes = []
for i in range(number_of_task):
tasks_to_accomplish.put("Task no " + str(i))
# création des processus
for w in range(number_of_processes):
p = Process(target=do_job, args=(tasks_to_accomplish, tasks_that_are_done))
processes.append(p)
p.start()
# achèvement du processus
for p in processes:
p.join()
# imprimer la sortie
while not tasks_that_are_done.empty():
print(tasks_that_are_done.get())
return True
if __name__ == '__main__':
main()
En fonction du nombre de tâches, le code prendra un certain temps pour vous montrer la sortie. La sortie du code suivant variera de temps en temps.
Python multiprocessing Pool
Le module Python multiprocessing Pool peut être utilisé pour l’exécution parallèle d’une fonction sur plusieurs valeurs d’entrée, en distribuant les données d’entrée entre les processus (parallélisme des données). Voici un exemple simple de multiprocessing Pool en Python.
from multiprocessing import Pool
import time
work = (["A", 5], ["B", 2], ["C", 1], ["D", 3])
def work_log(work_data):
print(" Process %s waiting %s seconds" % (work_data[0], work_data[1]))
time.sleep(int(work_data[1]))
print(" Process %s Finished." % work_data[0])
def pool_handler():
p = Pool(2)
p.map(work_log, work)
if __name__ == '__main__':
pool_handler()
L’image ci-dessous montre la sortie du programme ci-dessus. Remarquez que la taille de la piscine est de 2, donc deux exécutions de la fonction work_log
se déroulent en parallèle. Lorsqu’un des traitements de la fonction se termine, il prend l’argument suivant, et ainsi de suite. C’est tout pour le module multiprocessing en Python. Référence : Documentation officielle
Source:
https://www.digitalocean.com/community/tutorials/python-multiprocessing-example