Maison >développement back-end >Tutoriel Python >Gestion des processus en Python : principes fondamentaux de la programmation parallèle

Gestion des processus en Python : principes fondamentaux de la programmation parallèle

Patricia Arquette
Patricia Arquetteoriginal
2025-01-03 09:52:40133parcourir

Process Management in Python: Fundamentals of Parallel Programming

La programmation parallèle est un modèle de programmation qui permet à un programme d'exécuter plusieurs tâches simultanément sur plusieurs processeurs ou cœurs. Ce modèle vise à utiliser les ressources du processeur plus efficacement, à réduire le temps de traitement et à augmenter les performances.

Pour illustrer la programmation parallèle avec une image, on peut imaginer que nous avons un problème. Avant de commencer le traitement parallèle, nous divisons ce problème en sous-parties plus petites. Nous supposons que ces sous-parties sont indépendantes les unes des autres et n’ont aucune connaissance les unes des autres. Chaque sous-problème est traduit en tâches ou instructions plus petites. Ces tâches sont organisées de manière adaptée au travail parallèle. Par exemple, de nombreuses instructions peuvent être créées pour effectuer la même opération sur un ensemble de données. Ces tâches sont ensuite réparties sur différents processeurs. Chaque processeur traite les instructions qui lui sont assignées indépendamment et en parallèle. Ce processus réduit considérablement le temps total de traitement et nous permet d'utiliser les ressources plus efficacement.

Python propose plusieurs outils et modules pour la programmation parallèle.

**Multitraitement
**Il permet au programme de profiter d'un véritable parallélisme en lui permettant d'exécuter plusieurs processus en même temps. Le module multitraitement surmonte les limitations de GIL (Global Interpreter Lock), permettant d'obtenir des performances complètes sur les processeurs multicœurs.

Global Interpreter Lock (GIL) est un mécanisme utilisé dans l'implémentation populaire de Python appelée CPython. GIL autorise un seul thread à exécuter le bytecode Python à la fois. Il s'agit d'une construction qui limite le véritable parallélisme lorsque le multithreading est utilisé en Python.

*Exemple de calcul de carré et de cube
*

from multiprocessing import Process

def print_square(numbers):
    for n in numbers:
        print(f"Square of {n} is {n * n}")

def print_cube(numbers):
    for n in numbers:
        print(f"Cube of {n} is {n * n * n}")

if __name__ == "__main__":
    numbers = [2, 3, 4, 5]  

    # İşlemler (processes) oluşturma
    process1 = Process(target=print_square, args=(numbers,))
    process2 = Process(target=print_cube, args=(numbers,))

    # İşlemleri başlatma
    process1.start()
    process2.start()

    # İşlemlerin tamamlanmasını bekleme
    process1.join()
    process2.join()

Pourquoi nous avons besoin du multitraitement Nous pouvons expliquer la nécessité du multitraitement avec l'analogie d'un cuisinier et d'une cuisine. Vous pouvez imaginer un cuisinier cuisinant seul dans une cuisine comme un programme à processus unique. On peut comparer cela au multiprocessing lorsque plusieurs cuisiniers travaillent ensemble dans la même cuisine.

Processus unique - Cuisson unique

Il n'y a qu'un seul cuisinier dans une cuisine. Ce cuisinier réalisera trois plats différents : une entrée, un plat et un dessert. Chaque plat est réalisé tour à tour :
Il prépare et complète l'entrée.
Il passe au plat principal et le termine.
Enfin, il prépare le dessert.
Le problème :

Peu importe la rapidité avec laquelle le cuisinier est, il ou elle se relaye et cela fait perdre du temps en cuisine.
Si trois plats différents doivent être cuisinés en même temps, le temps sera plus long.
Multitraitement - De nombreux cuisiniers

Imaginez maintenant qu'il y ait trois cuisiniers dans la même cuisine. Chacun prépare un plat différent :
Un cuisinier prépare l'entrée.
Le deuxième cuisinier prépare le plat principal.
Le troisième cuisinier prépare le dessert.
Avantage :

Trois plats sont préparés en même temps, ce qui réduit considérablement le temps total.
Chaque cuisinier fait son propre travail de manière indépendante et n'est pas affecté par les autres.
Partage de données entre processus en Python
En Python, il est possible de partager des données entre différents processus grâce au module multitraitement. Cependant, chaque processus utilise son propre espace mémoire. Par conséquent, des mécanismes spéciaux sont utilisés pour partager des données entre les processus.

from multiprocessing import Process

def print_square(numbers):
    for n in numbers:
        print(f"Square of {n} is {n * n}")

def print_cube(numbers):
    for n in numbers:
        print(f"Cube of {n} is {n * n * n}")

if __name__ == "__main__":
    numbers = [2, 3, 4, 5]  

    # İşlemler (processes) oluşturma
    process1 = Process(target=print_square, args=(numbers,))
    process2 = Process(target=print_cube, args=(numbers,))

    # İşlemleri başlatma
    process1.start()
    process2.start()

    # İşlemlerin tamamlanmasını bekleme
    process1.join()
    process2.join()

Lorsque nous examinons l'exemple de code, nous constatons que la liste des résultats est vide. La raison principale en est que les processus créés avec le multitraitement fonctionnent dans leur propre espace mémoire, indépendamment du processus principal. En raison de cette indépendance, les modifications apportées au processus enfant ne sont pas directement reflétées dans les variables du processus principal.

Python fournit les méthodes suivantes pour partager des données :

**1. Mémoire partagée
**Les objets Value et Array sont utilisés pour partager des données entre les opérations.
Valeur : partage un seul type de données (par exemple, un nombre).
Tableau : utilisé pour partager un tableau de données.

import multiprocessing

result = []

def square_of_list(mylist):
    for num in mylist:
        result.append(num**2)
    return result

mylist= [1,3,4,5]

p1 = multiprocessing.Process(target=square_of_list,args=(mylist,))
p1.start()
p1.join()

print(result) # [] Boş Liste

**2. File d'attente
**Il utilise la structure FIFO (First In First Out) pour transférer des données entre les processus.
multiprocessing.Queue permet à plusieurs processus d'envoyer et de recevoir des données.

from multiprocessing import Process, Value

def increment(shared_value):
    for _ in range(1000):
        shared_value.value += 1  

if __name__ == "__main__":
    shared_value = Value('i', 0)  
    processes = [Process(target=increment, args=(shared_value,)) for _ in range(5)]

    for p in processes:
        p.start()
    for p in processes:
        p.join()

    print(f"Sonuç: {shared_value.value}")

**3. Tuyau
**multiprocessing.Pipe permet un transfert de données bidirectionnel entre deux processus.
Il peut être utilisé à la fois pour envoyer et recevoir des données.

from multiprocessing import Process, Queue

def producer(queue):
    for i in range(5):
        queue.put(i)  # Kuyruğa veri ekle
        print(f"Üretildi: {i}")

def consumer(queue):
    while not queue.empty():
        item = queue.get()  
        print(f"Tüketildi: {item}")

if __name__ == "__main__":
    queue = Queue()

    producer_process = Process(target=producer, args=(queue,))
    consumer_process = Process(target=consumer, args=(queue,))

    producer_process.start()
    producer_process.join()

    consumer_process.start()
    consumer_process.join()

*Remplissage entre les processus
*
Le « remplissage entre les processus » est souvent utilisé pour organiser la mémoire des processus ou pour éviter les problèmes d'alignement des données et de collision lors de l'accès aux données partagées entre plusieurs processus.

Ce concept est particulièrement important dans des cas tels que le faux partage de la ligne de cache. Un faux partage peut entraîner une perte de performances lorsque plusieurs processus tentent d'utiliser la mémoire partagée en même temps. Cela est dû au partage des lignes de cache dans les processeurs modernes.

**Synchronisation entre les processus
**Avec le module multitraitement de Python, plusieurs processus peuvent s'exécuter simultanément. Cependant, il est important d’utiliser la synchronisation lorsque plusieurs processus doivent accéder aux mêmes données. Cela est nécessaire pour garantir la cohérence des données et éviter des problèmes tels que les conditions de concurrence.

from multiprocessing import Process, Pipe

def send_data(conn):
    conn.send([1, 2, 3, 4])  
    conn.close()

if __name__ == "__main__":
    parent_conn, child_conn = Pipe()  

    process = Process(target=send_data, args=(child_conn,))
    process.start()

    print(f"Alınan veri: {parent_conn.recv()}")  # Veri al
    process.join()

Le verrouillage permet à un seul processus d'accéder aux données partagées à la fois.
Avant que le processus utilisant le verrou ne se termine, d'autres processus attendent.

**Multithreading

Le multithreading est un modèle de programmation parallèle qui permet à un programme d'exécuter plusieurs threads simultanément. Les threads sont des unités de code indépendantes plus petites qui s'exécutent au sein du même processus et visent un traitement plus rapide et plus efficace en partageant des ressources.
En Python, le module threading est utilisé pour développer des applications multithreading. Cependant, en raison du mécanisme GIL (Global Interpreter Lock) de Python, le multithreading offre des performances limitées sur les tâches liées au processeur. Par conséquent, le multithreading est généralement préféré pour les tâches liées aux E/S.

le fil est la séquence d'instructions de notre programme.

from multiprocessing import Process

def print_square(numbers):
    for n in numbers:
        print(f"Square of {n} is {n * n}")

def print_cube(numbers):
    for n in numbers:
        print(f"Cube of {n} is {n * n * n}")

if __name__ == "__main__":
    numbers = [2, 3, 4, 5]  

    # İşlemler (processes) oluşturma
    process1 = Process(target=print_square, args=(numbers,))
    process2 = Process(target=print_cube, args=(numbers,))

    # İşlemleri başlatma
    process1.start()
    process2.start()

    # İşlemlerin tamamlanmasını bekleme
    process1.join()
    process2.join()

**Synchronisation des threads
**La synchronisation des threads est une technique utilisée pour garantir la cohérence et l'ordre des données lorsque plusieurs threads accèdent simultanément aux mêmes ressources. En Python, le module threading fournit plusieurs outils de synchronisation.

**Pourquoi avoir besoin d'une synchronisation des threads ?
**Conditions de course :

Lorsque deux threads ou plus accèdent à une ressource partagée en même temps, des incohérences de données peuvent survenir.
Par exemple, un thread peut lire des données tandis qu'un autre thread met à jour les mêmes données.
*Cohérence des données :
*

La coordination entre les threads est nécessaire pour garantir que les ressources partagées sont correctement mises à jour.
Exemples d'outils de synchronisation en Python
**1. Verrouiller
**Lorsqu'un thread acquiert le verrou, il attend que le verrou soit libéré avant que d'autres threads puissent accéder à la même ressource.

import multiprocessing

result = []

def square_of_list(mylist):
    for num in mylist:
        result.append(num**2)
    return result

mylist= [1,3,4,5]

p1 = multiprocessing.Process(target=square_of_list,args=(mylist,))
p1.start()
p1.join()

print(result) # [] Boş Liste

2-Événement

from multiprocessing import Process, Value

def increment(shared_value):
    for _ in range(1000):
        shared_value.value += 1  

if __name__ == "__main__":
    shared_value = Value('i', 0)  
    processes = [Process(target=increment, args=(shared_value,)) for _ in range(5)]

    for p in processes:
        p.start()
    for p in processes:
        p.join()

    print(f"Sonuç: {shared_value.value}")

**Conclusion :
**La synchronisation des threads est essentielle pour éviter les incohérences des données lorsque les threads accèdent à des ressources partagées. En Python, des outils tels que Lock, RLock, Semaphore, Event et Condition fournissent des solutions efficaces en fonction des besoins de synchronisation. L'outil à utiliser dépend des besoins de l'application et des exigences de synchronisation.

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!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Article précédent:sous dans PyTorchArticle suivant:sous dans PyTorch