Direkt zum Inhalt

Python Multiprocessing: Ein Leitfaden zu Themen und Prozessen

Lerne, wie du Threads und Prozesse mit dem Python Multiprocessing-Modul verwaltest. Entdecke die wichtigsten Techniken für die parallele Programmierung. Verbessere die Effizienz deines Codes mit Beispielen.
Aktualisierte 13. Dez. 2024  · 7 Min. Lesezeit

Die Standardbibliothek von Python ist mit mehreren eingebauten Paketen ausgestattet, mit denen Entwickler sofort von den Vorteilen der Sprache profitieren können.

Ein solches Paket ist das Multiprocessing-Modul, mit dem die Systeme mehrere Prozesse gleichzeitig ausführen können. Mit anderen Worten: Entwickler können Anwendungen in kleinere Threads aufteilen, die unabhängig von ihrem Python-Code laufen können. Diese Threads oder Prozesse werden dann vom Betriebssystem dem Prozessor zugewiesen, so dass sie parallel laufen können und die Leistung und Effizienz deiner Python-Programme verbessert wird. 

Wenn dir Begriffe wie Threads, Prozesse, Prozessoren usw. nicht geläufig sind, mach dir keine Sorgen. In diesem Artikel werden wir die Definition eines Prozesses, den Unterschied zu Threads und die Verwendung des Moduls multiprocessing behandeln. 

Was sind Prozesse in Python?

Das Verständnis des Konzepts von Prozessen und Threads ist äußerst nützlich, um besser zu verstehen, wie ein Betriebssystem Programme in den verschiedenen Ausführungsphasen verwaltet. Ein Prozess ist lediglich ein Verweis auf ein Computerprogramm. Jedes Programm hat einen Prozess, der mit ihm verbunden ist. 

Wenn du diesen Artikel liest, ist es sehr wahrscheinlich, dass auf deinem Computer viele Prozesse gleichzeitig laufen, auch wenn du nur ein paar Programme geöffnet hast - das liegt daran, dass die meisten Betriebssysteme mehrere Aufgaben im Hintergrund laufen lassen. Es kann zum Beispiel sein, dass du in diesem Moment nur drei Programme laufen hast, aber auf deinem Computer können mehr als 30 aktive Prozesse gleichzeitig laufen. 

Wie du die aktiven Prozesse, die gerade auf deinem Computer laufen, überprüfen kannst, hängt von deinem Betriebssystem ab: 

  • Unter Windows: Mit Strg+Umschalt+Esc wird der Taskmanager gestartet 
  • Auf dem Mac: Öffne die Spotlight-Suche auf dem Mac und gib "Aktivitätsmonitor" ein, dann drücke den Zeilenschalter  
  • Unter Linux: Klicke auf Anwendungsmenü und suche nach System Monitor. 

Python ermöglicht den Zugriff auf echte Prozesse auf Systemebene. Wenn du eine Instanz der Klasse Process aus dem Multiprocessing-Modul instanziierst, können Entwickler den zugrunde liegenden nativen Prozess mit Python referenzieren. Ein neuer nativer Prozess wird im Hintergrund erstellt, wenn ein Prozess gestartet wird. Der Lebenszyklus eines Python-Prozesses besteht aus drei Phasen: Die Initiierung eines neuen Prozesses, der laufende Prozess und der beendete Prozess - wir werden jede Phase behandeln.

Alle Prozesse setzen sich aus einem oder mehreren Threads zusammen. Erinnerst du dich, dass wir erwähnt haben, dass "ein Prozess lediglich ein Verweis auf ein Computerprogramm ist"? Jedes Python-Programm ist ein Prozess, der aus einem Standard-Thread besteht, dem Haupt-Thread. Der Hauptthread ist für die Ausführung der Anweisungen in deinen Python-Programmen verantwortlich. Es ist jedoch wichtig zu wissen, dass Prozesse und Threads unterschiedlich sind. 

Multiprocessing vs. Einfädeln

Genauer gesagt, entspricht eine Instanz des Python-Interpreters - das Werkzeug, das den in Python geschriebenen Code in eine Sprache umwandelt, die ein Computer versteht - einem Prozess. Ein Prozess besteht aus mindestens einem Thread, der in Python "Haupt-Thread" genannt wird, obwohl auch andere Threads innerhalb desselben Prozesses erstellt werden können - alle anderen Threads, die innerhalb eines Prozesses erstellt werden, gehören zu diesem Prozess. 

Der Thread dient als Repräsentant dafür, wie dein Python-Programm ausgeführt wird. Sobald alle nicht im Hintergrund laufenden Threads beendet sind, wird der Python-Prozess beendet. 

  • Prozess: Ein Prozess ist eine Instanz des Python-Interpreters, die aus mindestens einem Thread, dem sogenannten Hauptthread, besteht. 
  • Thema: Eine Darstellung, wie ein Python-Programm innerhalb eines Python-Prozesses ausgeführt wird.

Python hat zwei sehr ähnliche Klassen, die uns mehr Kontrolle über Prozesse und Threads geben: multiprocessing.Process und threading.Thread.

Schauen wir uns einige ihrer Gemeinsamkeiten und Unterschiede an. 

Ähnlichkeiten

Gleichzeitigkeit

Gleichzeitigkeit ist ein Konzept, bei dem verschiedene Programmteile außer der Reihenfolge oder in Teilreihenfolge ausgeführt werden können, ohne dass das Endergebnis beeinflusst wird. Beide Klassen waren ursprünglich für die Gleichzeitigkeit gedacht. 

Unterstützung für Gleichzeitigkeitsprimitive

Das Multiprocessing.Process und Threading. Thread-Klassen unterstützen die gleichen Gleichzeitigkeits-Primitive - ein Werkzeug, das die Synchronisierung und Koordination von Threads und Prozessen ermöglicht. 

Einheitliche API

Sobald du das Multiprocessing verstanden hast. Process API, dann kannst du dieses Wissen auf die Threading.Thread API übertragen und umgekehrt. Sie wurden absichtlich so gestaltet. 

Unterschiede

Funktionsweise

Obwohl ihre APIs gleich sind, unterscheiden sich Prozesse und Threads. Ein Prozess ist eine höhere Abstraktionsebene als ein Thread: Ein Prozess ist ein Verweis auf ein Computerprogramm, und ein Thread gehört zu einem Prozess. Dieser Unterschied liegt in den Klassen begründet. Die Klassen repräsentieren also zwei verschiedene native Funktionen, die von einem zugrunde liegenden Betriebssystem verwaltet werden. 

Zugriff auf den gemeinsamen Zustand

Die beiden Klassen greifen unterschiedlich auf den gemeinsamen Status zu. Da Threads zu einem Prozess gehören, können sie sich den Speicher innerhalb eines Prozesses teilen. So hat eine Funktion, die in einem neuen Thread ausgeführt wird, immer noch Zugriff auf dieselben Daten und Zustände innerhalb eines Prozesses. Die Art und Weise, wie Threads Zustände miteinander teilen, wird als "Shared Memory" bezeichnet und ist ziemlich einfach. Im Gegensatz dazu ist die gemeinsame Nutzung von Zuständen zwischen Prozessen sehr viel aufwändiger: Der Zustand muss serialisiert und zwischen den Prozessen übertragen werden. Mit anderen Worten: Prozesse verwenden keinen gemeinsamen Speicher, um Zustände zu teilen, da sie über einen eigenen Speicher verfügen. Stattdessen werden Prozesse mithilfe einer Technik namens "Interprozesskommunikation" gemeinsam genutzt. Um diese in Python durchzuführen, sind andere explizite Werkzeuge wie multiprocessing.Pipe oder multiprocessing.Queue erforderlich. 

GIL

Die Python Global Interpreter Lock (GIL) ist eine Sperre, die es nur einem Thread erlaubt, die Kontrolle über den Python-Interpreter zu behalten. Mehrere Threads unterliegen der GIL, was die Verwendung von Python für Multithreading oft zu einer schlechten Idee macht: Echte Multi-Core-Ausführung durch Multithreading wird von Python auf dem CPython-Interpreter nicht unterstützt. Prozesse unterliegen jedoch nicht der GIL, da die GIL innerhalb jedes Python-Prozesses, aber nicht prozessübergreifend verwendet wird. 

In Bezug auf die Anwendungsfälle übertrifft Multiprocessing oft das Threading in Szenarien, in denen das Programm CPU-intensiv ist und keine IO oder Benutzerinteraktion durchführen muss. Threading ist die bessere Lösung für Programme, die IO- oder netzwerkgebunden sind und in Szenarien, in denen das Ziel darin besteht, die Anwendung reaktionsschneller zu machen. 

Die Vorteile von Python Multiprocessing

Stell dir einen Verarbeiter als Unternehmer vor. Wenn das Unternehmen des Unternehmers wächst, gibt es mehr Aufgaben, die bewältigt werden müssen, um mit dem Wachstum des Unternehmens Schritt zu halten. Wenn die Unternehmerin all diese Aufgaben (Buchhaltung, Verkauf, Marketing, Innovation usw.) allein übernimmt, läuft sie Gefahr, die Gesamteffizienz und -leistung des Unternehmens zu beeinträchtigen, da eine Person nur so viel auf einmal tun kann. Bevor sie zum Beispiel mit den Innovationsaufgaben weitermacht, muss sie die Verkaufsaufgaben stoppen - das nennt man "sequentielle Aufgaben". 

Die meisten Unternehmerinnen und Unternehmer wissen, dass es eine schlechte Idee ist, alles alleine machen zu wollen. Daher gleichen sie die wachsende Zahl von Aufgaben in der Regel durch die Einstellung von Mitarbeitern aus, die verschiedene Abteilungen leiten. Auf diese Weise können Aufgaben parallel ausgeführt werden - das heißt, eine Aufgabe muss nicht angehalten werden, damit eine andere ausgeführt werden kann. Mehr Beschäftigte für bestimmte Aufgaben einzustellen, ist so, als ob man mehrere Prozessoren für die Ausführung von Aufgaben einsetzt. Computer-Vision-Projekte sind zum Beispiel sehr anspruchsvoll, da du in der Regel viele Bilddaten verarbeiten musst, was sehr zeitaufwändig ist: Um diesen Vorgang zu beschleunigen, könntest du mehrere Bilder parallel verarbeiten. 

Wir können also sagen, dass Multiprocessing nützlich ist, um Programme effizienter zu machen, indem Aufgaben auf verschiedene Prozessoren aufgeteilt und zugewiesen werden. Das Multiprocessing-Modul von Python vereinfacht dies noch weiter, indem es als High-Level-Tool zur Steigerung der Effizienz deiner Programme dient, indem es Aufgaben verschiedenen Prozessen zuweist. 

Die Grundlagen des Python-Moduls Multiprocessing 

Wir haben bereits erwähnt, dass der Lebenszyklus eines Python-Prozesses aus drei Phasen besteht: dem neuen Prozess, dem laufenden Prozess und dem beendeten Prozess. In diesem Abschnitt werden die einzelnen Phasen des Lebenszyklus vertieft und mit Beispielen unterlegt. Du kannst den Code in unserer DataLab-Arbeitsmappe abrufen, um mitzumachen. 

Der neue Prozess 

Ein neuer Prozess kann als Prozess definiert werden, der durch Instanziierung einer Instanz der Klasse Process erstellt wurde. Ein Kindprozess wird gestartet, wenn wir das Objekt Process einer Variablen zuweisen. 

from multiprocessing import Process

# Create a new process
process = Process()

Im Moment tut unsere Prozessinstanz noch nichts, weil wir ein leeres Prozessobjekt initialisiert haben. Wir können die Konfigurationen unseres Prozessobjekts ändern, um eine bestimmte Funktion auszuführen, indem wir eine Funktion, die wir in einem anderen Prozess ausführen wollen, an den Zielparameter der Klasse übergeben. 

# Create a new process with a specified function to execute.
def example_function():
    pass

new_process = Process(target=example_function)

Wenn unsere Zielfunktion auch Parameter hätte, würden wir sie einfach als Tupel an den Parameter args des Process-Objekts übergeben.

Tipp: Lerne mit dem interaktiven Kurs Funktionen in Python schreiben, wie man Funktionen in Python schreibt. 

# Create a new process with specific function to execute with args.
def example(args):
    pass

process = Process(target=example, args=("Hi",))

Beachte, dass wir nur einen neuen Prozess erstellt haben, der aber noch nicht läuft. 

Schauen wir uns an, wie wir einen neuen Prozess starten können.  

Der laufende Prozess 

Einen neuen Prozess zu starten ist ganz einfach: Rufe einfach die Methode start() der Prozessinstanz auf. 

# Run the new process
process.start()

 Mit dieser Aktion wird die Aktivität des Prozesses gestartet, indem die Methode run() der Process-Instanz unter der Haube aufgerufen wird. Die Methode run() ist auch dafür verantwortlich, die benutzerdefinierte Funktion aufzurufen, die im Zielparameter der Prozessinstanz angegeben ist (falls angegeben).

Du erinnerst dich daran, dass wir weiter oben im Lernprogramm gesagt haben, dass jeder Prozess mindestens einen Thread hat, der Hauptthread genannt wird - das ist die Standardeinstellung. Wenn also ein Kindprozess gestartet wird, wird der Hauptthread für diesen Kindprozess erstellt und gestartet. Der Haupt-Thread ist für die Ausführung unseres gesamten Codes im Kindprozess verantwortlich. 

Wir können überprüfen, ob unser Prozess vom Zeitpunkt der Rückkehr der Methode start() bis zur Beendigung des Kindprozesses aktiv ist, indem wir die Methode is_alive() auf unserer Instanz Process verwenden. 

Hinweis: Wenn du dies in einem Notebook testest, muss sich der Aufruf von is_alive() in derselben Zelle befinden wie der Aufruf der Methode start(), damit der laufende Prozess abgefangen wird. 

# Run the new process
process.start()

# Check process is running
process.is_alive()

"""
True
"""

Wenn der Prozess nicht läuft, würde der Aufruf der Methode is_alive() False zurückgeben. 

Der abgebrochene Prozess

Wenn die Funktion run() zurückkehrt oder beendet wird, ist der Prozess beendet: Wir müssen nicht unbedingt etwas explizit tun. Mit anderen Worten: Du kannst erwarten, dass ein Prozess beendet wird, nachdem die Anweisungen, die du als Zielfunktion festgelegt hast, abgeschlossen sind. Die Methode is_alive() würde also false zurückgeben. 

# Check process is terminated - should return false.
process.is_alive()

"""
False
"""

Ein Prozess kann aber auch beendet werden, wenn er auf eine unbehandelte Ausnahme trifft oder ein Fehler auftritt. Wenn zum Beispiel ein Fehler in der Funktion auftritt, die du als Ziel festgelegt hast, wird der Prozess abgebrochen. 

# Create a new process with a specific function that has an error
# to execute with args.
def example(args):
    split_args = list(args.split())
    # "name" variable is not in the function namespace - should raise error
    return name

# New process
process = Process(target=example, args=("Hi",))

# Running the new process
process.start()

# Check process is running
process.is_alive()

"""
True

Process Process-15:
Traceback (most recent call last):
  File "/usr/lib/python3.8/multiprocessing/process.py", line 315, in _bootstrap
    self.run()
"""

Das Process-Objekt verfügt außerdem über die Methoden terminate() und kill(), mit denen du einen Prozess zwangsweise beenden kannst. 

# Create a new process with a specific function to execute with args.
def example(args):
    split_args = list(args.split())
    # "name" variable is not in the function namespace - should raise error
    return split_args

# New process
process = Process(target=example, args=("Hi",))

# Running the new process
process.start()

if process.is_alive():
    process.terminate() # You can also use process.kill()
    print("Process terminated forcefully")

"""
Process terminated forcefully
"""

Es ist wichtig zu beachten, dass erzwungene Beendigungen nicht der empfohlene Weg sind, um einen Prozess zu beenden: Sie können nicht alle offenen Ressourcen sicher schließen oder den erforderlichen Programmstatus speichern. Eine bessere Lösung ist ein kontrolliertes Herunterfahren mit einem prozesssicheren booleschen Flag oder einem ähnlichen Tool. 

Python Multiprocessing Tutorial

Nachdem du nun die Grundlagen des Multiprocessing verstanden hast, wollen wir dir anhand eines Beispiels zeigen, wie du in Python nebenläufig programmieren kannst. 

Die Funktion, die wir erstellen, wird einfach eine Anweisung ausgeben, 1 Sekunde lang schlafen und dann einen weiteren Schlaf ausgeben - erfahre mehr über Funktionen in diesem Python-Funktionen-Tutorial

import time

def do_something():
    print("I'm going to sleep")
    time.sleep(1)
    print("I'm awake") 

Der erste Schritt besteht darin, einen neuen Prozess zu erstellen: Wir werden zwei erstellen. 

# Create new child process

process_1 = Process(target=do_something)
process_2 = Process(target=do_something)

So sieht ein gleichzeitiges Programm in einer Notebook-Umgebung aus: 

%%time

# Starts both processes
process_1.start()
process_2.start()

"""
I'm going to sleep
CPU times: user 810 µs, sys: 7.34 ms, total: 8.15 ms
Wall time: 6.04 ms
I'm going to sleep
"""

Angesichts der Ausgabe des Programms ist es ziemlich offensichtlich, dass es irgendwo in unserem Code ein Problem gibt. Der Timer wird auf halbem Weg durch unseren ersten Prozess gedruckt und die zweite Druckanweisung wird nicht gedruckt. 

Dies geschieht, weil drei Prozesse laufen: der Hauptprozess, process_1 und process_2. Der Prozess, der die Zeit erfasst und ausdruckt, ist der Hauptprozess. Damit unser Hauptprozess warten kann, bevor er die Uhrzeit ausgibt, müssen wir die Methode join() für unsere beiden Prozesse aufrufen, nachdem wir sie gestartet haben.

Hinweis: Wenn du mehr darüber erfahren möchtest, schau dir diese Stackoverflow-Diskussion an. 

Schauen wir uns unser neues Code-Snippet an: 

%%time
​
# Create new child process (Cannot run a process more than once)
new_process_1 = Process(target=do_something)
new_process_2 = Process(target=do_something)
​
# Starts both processes
new_process_1.start()
new_process_2.start()
​
new_process_1.join()
new_process_2.join()

"""
I'm going to sleep
I'm going to sleep
I'm awake
I'm awake
CPU times: user 0 ns, sys: 14 ms, total: 14 ms
Wall time: 1.01 s
"""

Problem gelöst. 

Die Wandzeit war bei diesem Lauf etwas länger als beim ersten Lauf. In diesem Durchlauf wurden jedoch die Aufrufe unserer beiden Zielfunktionen abgeschlossen, bevor die Zeitinformationen zurückgegeben wurden. Wir können dieselbe Argumentation auch anwenden, um mehr Prozesse gleichzeitig laufen zu lassen. 

Abschließende Überlegungen zu Python Multiprocessing

In diesem Lernprogramm hast du gelernt, wie du Python-Programme effizienter machen kannst, indem du sie gleichzeitig ausführst. Genauer gesagt, hast du gelernt: 

  • Was Prozesse sind und wie du sie auf deinem Computer anzeigen kannst.
  • Die Gemeinsamkeiten und Unterschiede zwischen den Python- Modulen für Multiprocessing und Threading.
  • Die Grundlagen des Multiprocessing-Moduls und wie du ein Python-Programm mit Multiprocessing gleichzeitig ausführen kannst. 

Willst du mehr über die Programmierung in Python erfahren? Schau dir unseren Lernpfad für Python-Programmierer/innen an. Am Ende des Lernpfads wirst du die notwendigen Fähigkeiten erworben haben, um erfolgreich Software zu entwickeln, Daten zu verarbeiten und fortgeschrittene Analysen in Python durchzuführen. 

Werde ein Python-Entwickler

Erwerbe die Programmierkenntnisse, die alle Python-Entwickler/innen brauchen.
Kostenloses Lernen Beginnen

Kurtis Pykes 's photo
Author
Kurtis Pykes
LinkedIn
Themen

Kurse für Python

Zertifizierung verfügbar

Kurs

Intermediate Python

4 hr
1.2M
Verbessere deine Data Science-Fähigkeiten, indem du mit Matplotlib Visualisierungen erstellst und DataFrames mit Pandas manipulierst.
Siehe DetailsRight Arrow
Kurs Starten
Mehr anzeigenRight Arrow
Verwandt

Der Blog

Die 20 besten Snowflake-Interview-Fragen für alle Niveaus

Bist du gerade auf der Suche nach einem Job, der Snowflake nutzt? Bereite dich mit diesen 20 besten Snowflake-Interview-Fragen vor, damit du den Job bekommst!
Nisha Arya Ahmed's photo

Nisha Arya Ahmed

20 Min.

Der Blog

Die 32 besten AWS-Interview-Fragen und Antworten für 2024

Ein kompletter Leitfaden zur Erkundung der grundlegenden, mittleren und fortgeschrittenen AWS-Interview-Fragen, zusammen mit Fragen, die auf realen Situationen basieren. Es deckt alle Bereiche ab und sorgt so für eine abgerundete Vorbereitungsstrategie.
Zoumana Keita 's photo

Zoumana Keita

30 Min.

Der Blog

Top 30 Generative KI Interview Fragen und Antworten für 2024

Dieser Blog bietet eine umfassende Sammlung von Fragen und Antworten zu generativen KI-Interviews, die von grundlegenden Konzepten bis hin zu fortgeschrittenen Themen reichen.
Hesam Sheikh Hassani's photo

Hesam Sheikh Hassani

15 Min.

See MoreSee More