Das multiprocessing-Modul in Python bietet ein leistungsstarkes Werkzeug zur Erstellung paralleler Programme, die Mehrkernprozessoren effizient nutzen. Im Gegensatz zur standardmäßigen Threading-Programmierung, die durch den Global Interpreter Lock (GIL) eingeschränkt ist, ermöglicht multiprocessing den gleichzeitigen Start mehrerer Prozesse, von denen jeder über einen eigenen Speicher und eine unabhängige Ausführung verfügt.
Grundprinzipien der Arbeit mit multiprocessing
Multiprocessing in Python basiert auf der Erstellung separater Prozesse, die parallel auf verschiedenen Prozessorkernen ausgeführt werden können. Jeder Prozess arbeitet in einem isolierten Speicherbereich, was die für Threading typischen Probleme mit gemeinsam genutzten Daten vermeidet.
Zu den Schlüsselkomponenten des multiprocessing-Moduls gehören:
- Process — Klasse zum Erstellen und Verwalten einzelner Prozesse
- Pool — Prozesspool für die effiziente Ausführung vieler Aufgaben
- Queue — Warteschlangen für die sichere Datenübertragung zwischen Prozessen
- Lock — Synchronisationsmechanismen zur Steuerung des Ressourcenzugriffs
- Manager — Objekte zur Verwaltung gemeinsam genutzter Daten
Wann sollte man multiprocessing einsetzen?
Multiprocessing ist in folgenden Fällen am effektivsten:
CPU-intensive Aufgaben: Mathematische Berechnungen, Bildverarbeitung, Datenanalyse, wissenschaftliche Berechnungen. Solche Aufgaben profitieren von der parallelen Ausführung auf verschiedenen Prozessorkernen.
Verarbeitung großer Datenmengen: Wenn dieselbe Funktion auf viele Elemente angewendet werden muss, kann multiprocessing die Ausführung erheblich beschleunigen.
Unabhängige Aufgaben: Operationen, die keinen häufigen Datenaustausch zwischen Prozessen erfordern.
Für I/O-intensive Aufgaben (Dateiarbeit, Netzwerkanfragen) sind asynchrone Programmierung (asyncio) oder Threading besser geeignet.
Erstellen und Verwalten von Prozessen
Basisbeispiel mit der Process-Klasse
import multiprocessing
import time
def worker_task(name, duration):
"""Funktion zur Ausführung in einem separaten Prozess"""
print(f"Prozess {name} hat die Arbeit aufgenommen")
time.sleep(duration)
print(f"Prozess {name} hat die Arbeit beendet")
if __name__ == "__main__":
# Prozesse erstellen
process1 = multiprocessing.Process(target=worker_task, args=("Worker-1", 3))
process2 = multiprocessing.Process(target=worker_task, args=("Worker-2", 2))
# Prozesse starten
start_time = time.time()
process1.start()
process2.start()
# Auf das Ende der Prozesse warten
process1.join()
process2.join()
end_time = time.time()
print(f"Gesamtausführungszeit: {end_time - start_time:.2f} Sekunden")
Vererbung von der Process-Klasse
import multiprocessing
import os
import time
class CustomProcess(multiprocessing.Process):
def __init__(self, name, work_count):
super().__init__()
self.name = name
self.work_count = work_count
def run(self):
"""Methode, die im Prozess ausgeführt wird"""
print(f"Prozess {self.name} (PID: {os.getpid()}) hat die Arbeit aufgenommen")
for i in range(self.work_count):
print(f"{self.name}: führe Aufgabe {i+1} aus")
time.sleep(1)
print(f"Prozess {self.name} hat die Arbeit beendet")
if __name__ == "__main__":
processes = []
# Mehrere Prozesse erstellen
for i in range(3):
p = CustomProcess(f"Process-{i+1}", 3)
processes.append(p)
p.start()
# Auf das Ende aller Prozesse warten
for p in processes:
p.join()
Arbeiten mit dem Prozesspool
Der Pool bietet eine bequeme Schnittstelle zur Verwaltung