Heim >Backend-Entwicklung >Python-Tutorial >Prozessmanagement in Python: Grundlagen der parallelen Programmierung
Parallele Programmierung ist ein Programmiermodell, das es einem Programm ermöglicht, mehrere Aufgaben gleichzeitig auf mehreren Prozessoren oder Kernen auszuführen. Dieses Modell zielt darauf ab, Prozessorressourcen effizienter zu nutzen, die Verarbeitungszeit zu verkürzen und die Leistung zu steigern.
Um die parallele Programmierung mit einem Bild zu veranschaulichen, können wir uns vorstellen, dass wir ein Problem haben. Bevor wir mit der Parallelverarbeitung beginnen, teilen wir dieses Problem in kleinere Unterteile auf. Wir gehen davon aus, dass diese Unterteile unabhängig voneinander sind und kein Wissen voneinander haben. Jedes Teilproblem wird in kleinere Aufgaben oder Anweisungen übersetzt. Diese Aufgaben sind so organisiert, dass sie für paralleles Arbeiten geeignet sind. Beispielsweise können viele Anweisungen erstellt werden, um denselben Vorgang an einem Datensatz auszuführen. Diese Aufgaben werden dann auf verschiedene Prozessoren verteilt. Jeder Prozessor verarbeitet die ihm zugewiesenen Anweisungen unabhängig und parallel. Dieser Prozess reduziert die Gesamtbearbeitungszeit erheblich und ermöglicht uns einen effizienteren Ressourceneinsatz.
Python bietet mehrere Tools und Module für die parallele Programmierung.
**Mehrfachverarbeitung
**Dadurch kann das Programm echte Parallelität nutzen, indem es mehrere Prozesse gleichzeitig ausführen kann. Das Multiprocessing-Modul überwindet die Einschränkungen von GIL (Global Interpreter Lock) und ermöglicht so die volle Leistung auf Multi-Core-Prozessoren.
Global Interpreter Lock (GIL) ist ein Mechanismus, der in der beliebten Python-Implementierung namens CPython verwendet wird. GIL erlaubt jeweils nur einem Thread die Ausführung von Python-Bytecode. Dies ist ein Konstrukt, das die echte Parallelität einschränkt, wenn Multithreading in Python verwendet wird.
*Beispiel für eine Quadrat- und Würfelberechnung
*
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()
Warum wir Multiprocessing brauchen Wir können die Notwendigkeit von Multiprocessing mit der Analogie eines Kochs und einer Küche erklären. Sie können sich einen Koch, der allein in einer Küche kocht, als ein Programm mit nur einem Prozess vorstellen. Wir können es mit Multiprocessing vergleichen, wenn mehr als ein Koch in derselben Küche zusammenarbeitet.
Einzelprozess – Einzelkochen
In einer Küche gibt es nur einen Koch. Dieser Koch wird drei verschiedene Gerichte zubereiten: eine Vorspeise, ein Hauptgericht und ein Dessert. Jedes Gericht wird der Reihe nach zubereitet:
Er bereitet den Starter vor und stellt ihn fertig.
Er geht zum Hauptgang über und beendet ihn.
Zum Schluss macht er den Nachtisch.
Das Problem:
Egal wie schnell der Koch ist, er oder sie wechselt sich ab und das verschwendet Zeit in der Küche.
Wenn drei verschiedene Gerichte gleichzeitig zubereitet werden müssen, dauert es länger.
Multiprocessing – Viele Köche
Stellen Sie sich nun vor, dass in derselben Küche drei Köche arbeiten. Jeder bereitet ein anderes Gericht zu:
Ein Koch macht die Vorspeise.
Der zweite Koch bereitet den Hauptgang zu.
Der dritte Koch macht den Nachtisch.
Vorteil:
Drei Gerichte werden gleichzeitig zubereitet, was die Gesamtzeit deutlich verkürzt.
Jeder Koch erledigt seine eigene Arbeit unabhängig und wird von den anderen nicht beeinflusst.
Daten zwischen Prozessen in Python teilen
In Python ist es mithilfe des Multiprocessing-Moduls möglich, Daten zwischen verschiedenen Prozessen auszutauschen. Allerdings nutzt jeder Prozess seinen eigenen Speicherplatz. Daher werden spezielle Mechanismen verwendet, um Daten zwischen Prozessen auszutauschen.
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()
Wenn wir das Codebeispiel untersuchen, stellen wir fest, dass die Ergebnisliste leer ist. Der Hauptgrund hierfür liegt darin, dass die mit Multiprocessing erstellten Prozesse unabhängig vom Hauptprozess in einem eigenen Speicherbereich arbeiten. Aufgrund dieser Unabhängigkeit werden im untergeordneten Prozess vorgenommene Änderungen nicht direkt in den Variablen im Hauptprozess widergespiegelt.
Python bietet die folgenden Methoden zum Teilen von Daten:
**1. Gemeinsamer Speicher
**Wert- und Array-Objekte werden verwendet, um Daten zwischen Operationen auszutauschen.
Wert: Gibt einen einzelnen Datentyp gemeinsam (z. B. eine Zahl).
Array: Wird zum Teilen eines Datenarrays verwendet.
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. Warteschlange
**Es verwendet die FIFO-Struktur (First In First Out), um Daten zwischen Prozessen zu übertragen.
multiprocessing.Queue ermöglicht mehreren Prozessen das Senden und Empfangen von Daten.
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. Pfeife
**multiprocessing.Pipe ermöglicht die bidirektionale Datenübertragung zwischen zwei Prozessen.
Es kann sowohl zum Senden als auch zum Empfangen von Daten verwendet werden.
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()
*Auffüllen zwischen Prozessen
*„Auffüllen zwischen Prozessen“ wird häufig zur Organisation des Prozessspeichers oder zur Vermeidung von Datenausrichtungs- und Kollisionsproblemen beim Zugriff auf Daten verwendet, die von mehreren Prozessen gemeinsam genutzt werden.
Dieses Konzept ist besonders wichtig in Fällen wie der falschen Freigabe von Cache-Zeilen. Falsches Teilen kann zu Leistungseinbußen führen, wenn mehrere Prozesse gleichzeitig versuchen, gemeinsam genutzten Speicher zu nutzen. Dies ist auf die gemeinsame Nutzung von Cache-Zeilen in modernen Prozessoren zurückzuführen.
**Synchronisation zwischen Prozessen
**Mit dem Multiprocessing-Modul in Python können mehrere Prozesse gleichzeitig ausgeführt werden. Allerdings ist es wichtig, die Synchronisierung zu verwenden, wenn mehrere Prozesse auf dieselben Daten zugreifen müssen. Dies ist notwendig, um die Konsistenz der Daten sicherzustellen und Probleme wie Rennbedingungen zu vermeiden.
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()
Sperre ermöglicht jeweils nur einem Prozess den Zugriff auf freigegebene Daten.
Bevor der Prozess, der die Sperre verwendet, abgeschlossen ist, warten andere Prozesse.
**Multithreading
Multithreading ist ein paralleles Programmiermodell, das es einem Programm ermöglicht, mehrere Threads gleichzeitig auszuführen. Threads sind kleinere unabhängige Codeeinheiten, die innerhalb desselben Prozesses ausgeführt werden und durch die gemeinsame Nutzung von Ressourcen eine schnellere und effizientere Verarbeitung ermöglichen.
In Python wird das Threading-Modul zur Entwicklung von Multithreading-Anwendungen verwendet. Aufgrund des Global Interpreter Lock (GIL)-Mechanismus von Python bietet Multithreading jedoch eine begrenzte Leistung bei CPU-gebundenen Aufgaben. Daher wird Multithreading im Allgemeinen für E/A-gebundene Aufgaben bevorzugt.
Thread ist die Abfolge von Anweisungen in unserem Programm.
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()
**Thread-Synchronisierung
**Thread-Synchronisierung ist eine Technik, die verwendet wird, um Datenkonsistenz und -reihenfolge sicherzustellen, wenn mehrere Threads gleichzeitig auf dieselben Ressourcen zugreifen. In Python stellt das Threading-Modul mehrere Tools zur Synchronisierung bereit.
**Warum ist eine Thread-Synchronisierung erforderlich?
**Rennbedingungen:
Wenn zwei oder mehr Threads gleichzeitig auf eine gemeinsam genutzte Ressource zugreifen, kann es zu Dateninkonsistenzen kommen.
Beispielsweise kann ein Thread Daten lesen, während ein anderer Thread dieselben Daten aktualisiert.
*Datenkonsistenz:
*
Die Koordination zwischen Threads ist erforderlich, um sicherzustellen, dass gemeinsam genutzte Ressourcen korrekt aktualisiert werden.
Beispiele für Synchronisierungstools in Python
**1. Sperren
**Wenn ein Thread die Sperre erhält, wartet er auf die Freigabe der Sperre, bevor andere Threads auf dieselbe Ressource zugreifen können.
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-Event
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}")
**Fazit:
**Thread-Synchronisierung ist entscheidend, um Dateninkonsistenzen zu verhindern, wenn Threads auf gemeinsam genutzte Ressourcen zugreifen. In Python bieten Tools wie Lock, RLock, Semaphore, Event und Condition effektive Lösungen entsprechend den Synchronisierungsanforderungen. Welches Tool verwendet werden soll, hängt von den Anforderungen der Anwendung und den Synchronisierungsanforderungen ab.
Das obige ist der detaillierte Inhalt vonProzessmanagement in Python: Grundlagen der parallelen Programmierung. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!