Python Probleme mit gemeinsam genutztem Speicher beheben und gemeinsam genutzte Ressourcen sperren
-
Verwenden Sie
multiprocessing.Array()
, um Shared Memory in Python zu verwenden -
Verwenden Sie
multiprocessing.Lock()
, um die freigegebenen Ressourcen in Python zu sperren
Dieses Tutorial erläutert verschiedene Aspekte von Multiprocessing Shared Memory und zeigt, wie Probleme mit Shared Memory behoben werden können. Wir werden auch lernen, wie man die Sperre
verwendet, um die gemeinsam genutzten Ressourcen in Python zu sperren.
Verwenden Sie multiprocessing.Array()
, um Shared Memory in Python zu verwenden
Einer der kritischsten Aspekte von multiprocessing
ist die gemeinsame Nutzung der Daten zwischen den Prozessen, wenn Sie mehrere untergeordnete Prozesse haben.
Eine der wesentlichen Eigenschaften der Kindprozesse, die Sie mit Hilfe der Fähigkeiten des processing
-Moduls erstellen, ist, dass sie unabhängig laufen und über einen eigenen Speicherplatz verfügen.
Das bedeutet, dass der Prozess des Kindes etwas Speicherplatz haben wird. Und jede Variable versucht, in ihrem eigenen Speicherbereich zu erstellen oder wird geändert, nicht im Speicherbereich ihres übergeordneten Elements.
Lassen Sie uns versuchen, dieses Konzept zu verstehen, indem wir ein Beispiel nehmen und in den Code springen, indem wir das multiprocessing
-Modul importieren.
Wir haben eine leere Liste namens RESULT
erstellt und eine Funktion namens Make_Sqaured_List()
definiert, die die Elemente einer gegebenen Liste quadriert und an unsere globale RESULT
-Liste anhängt.
Das Objekt Procc_1
entspricht der Klasse Process()
und setzt als Ziel die Funktion Make_Sqaured_List
ohne Klammern.
Und an den Parameter args
übergeben wir eine separate Liste namens Items_list
, die als Argument an die Funktion Make_Sqaured_List()
übergeben wird.
Beispielcode:
import multiprocessing
RESULT = []
def Make_Sqaured_List(Num_List):
global RESULT
for n in Num_List:
RESULT.append(n ** 2)
print(f"Result: {RESULT}")
if __name__ == "__main__":
Items_list = [5, 6, 7, 8]
Procc_1 = multiprocessing.Process(target=Make_Sqaured_List, args=(Items_list,))
Procc_1.start()
Procc_1.join()
Lassen Sie uns diesen untergeordneten Prozess ausführen, und wir erhalten das Ergebnis gemäß unserem untergeordneten Prozess, nämlich den Wert der globalen Liste.
Result: [25, 36, 49, 64]
Aber wenn Sie versuchen, die noch leere Liste ERGEBNIS
zu drucken, was passiert dann mit der Liste ERGEBNIS
?
print(RESULT)
Ausgang:
[]
Gemäss unserem Hauptprozess ist unser Elternprozess noch leer, während gemäss dem Kindprozess die RESULT
-Liste Inhalt hat. Es bedeutet einfach, dass unsere beiden unterschiedlichen Prozesse unterschiedliche Speicherbereiche haben.
Wir können dies anhand eines Szenarios verstehen, in dem wir Prozess 1 haben, das ist unser Hauptprogramm, in dem wir zunächst eine leere RESULT
-Liste haben.
Und wenn wir einen untergeordneten Prozess erstellen, hat dieser zunächst ebenfalls einen leeren Wert, und dann wird die Funktion Make_Sqaured_List()
ausgeführt, sodass die Liste RESULT
einige Elemente enthält. Da wir aber in diesem Speicherbereich vom übergeordneten Prozess auf RESULT
zugreifen, sind die Änderungen nicht sichtbar.
Beispielcode:
import multiprocessing
RESULT = []
def Make_Sqaured_List(Num_List):
global RESULT
for n in Num_List:
RESULT.append(n ** 2)
print(f"Result: {RESULT}")
if __name__ == "__main__":
Items_list = [5, 6, 7, 8]
Procc_1 = multiprocessing.Process(target=Make_Sqaured_List, args=(Items_list,))
Procc_1.start()
Procc_1.join()
print(RESULT)
Ausgang:
Result: [25, 36, 49, 64]
[]
Also, was ist die Lösung dafür? Aber zuerst wollen wir sehen, wie wir es lösen können.
Lösung zur Behebung der Probleme bei der gemeinsamen Nutzung von Daten zwischen Multiprocessing
In diesem Abschnitt werden wir die Lösung sehen, die uns hilft, den Wert aller Änderungen zu ermitteln und das Problem mit der gemeinsamen Nutzung von Daten zwischen den Multiprocessing zu beheben.
Die Lösung heißt Shared Memory. Das multiprocessing
-Modul stellt uns zwei Arten von Objekten namens Array
und Value
zur Verfügung, die verwendet werden können, um die Daten zwischen den Prozessen zu teilen.
Das Array
ist ein Array, das aus dem gemeinsam genutzten Speicher zugewiesen wird; Im Grunde gibt es einen Teil Ihres Computerspeichers, den wir gemeinsam genutzten Speicher nennen können, oder einen Bereich, auf den mehrere Prozesse zugreifen können.
In diesem gemeinsamen Speicher erstellen wir also ein neues Array oder einen neuen Wert. Diese Mehrwerte sind nicht unsere grundlegenden Python-Datenstrukturen; Es gibt etwas anderes und ist im Modul multiprocessing
selbst definiert.
Nun deklarieren wir ein Objekt namens RESULT_ARRAY
mit multiprocessing.Array()
. Dann müssen wir in diesem Array den Datentyp übergeben. Wir übergeben i
als String, was bedeutet, dass wir ganzzahlige Werte darin einfügen, und wir müssen die Größe
angeben.
Beispielcode:
RESULT_ARRAY = multiprocessing.Array("i", 4)
Es ist mit einem Array im C-Programmierstil verwandt, sodass wir die Größe gleichzeitig angeben können. Auf diese Weise können wir Objekte am gewünschten Ort speichern.
Jetzt erstellen wir einen neuen Wert namens OBJ_Sum
, der gleich multiprocessing.Value()
ist, und der Wert wird gespeichert und eingegeben.
Beispielcode:
OBJ_Sum = multiprocessing.Value("i")
Als nächstes erstellen wir ein Objekt namens procc_1
, das gleich multiprocessing.Process()
ist, das wir eine Funktion nennen werden. Wir haben eine Funktion namens Make_Sqaured_List()
erstellt, die drei Argumente annehmen wird:
- Eine Liste
- Ein Array-Objekt
- Ein Wertobjekt.
Wir werden diese drei Argumente mit diesem Process
-Argument namens args
an unsere Funktion übergeben. Sehen Sie sich beispielsweise den folgenden Codezaun an.
Beispielcode:
Procc_1 = multiprocessing.Process(
target=Make_Sqaured_List, args=(Items_list, RESULT_ARRAY, OBJ_Sum)
)
In der Funktion Make_Sqaured_List()
werden wir nun Items_list
mit der Funktion enumerate()
iterieren. Damit wir den index
und Wert
von Items_list
erhalten können.
Es ist ein Array im C-Stil, daher müssen wir die Indizierung verwenden, um die Werte unserem Array zuzuweisen. Wir werden auch die Werte eines Arrays summieren, und OBJ_Sum.value
ist eine Eigenschaft von multiprocessing.Value()
.
Beispielcode:
def Make_Sqaured_List(Items_list, RESULT, OBJ_Sum):
for i, n in enumerate(Items_list):
RESULT[i] = n ** 2
OBJ_Sum.value = sum(RESULT)
Wir haben in unserem Hauptprozess einige Variablen definiert, die die vom untergeordneten Prozess aufgerufene Funktion ändern. Unsere Hauptagenda ist also, ob wir diese geänderten Werte in unseren Hauptprozess übernehmen können oder nicht.
Jetzt können wir auf das im untergeordneten Prozess reflektierte Array zugreifen und seine Summe mit OBJ_Sum.value
erhalten. Sehen Sie sich beispielsweise das folgende Code-Snippet an.
Beispielcode:
import multiprocessing
def Make_Sqaured_List(Items_list, RESULT, OBJ_Sum):
for i, n in enumerate(Items_list):
RESULT[i] = n ** 2
OBJ_Sum.value = sum(RESULT)
if __name__ == "__main__":
Items_list = [5, 6, 7, 8]
RESULT_ARRAY = multiprocessing.Array("i", 4)
OBJ_Sum = multiprocessing.Value("i")
Procc_1 = multiprocessing.Process(
target=Make_Sqaured_List, args=(Items_list, RESULT_ARRAY, OBJ_Sum)
)
Procc_1.start()
Procc_1.join()
print(RESULT_ARRAY[:])
print(OBJ_Sum.value)
Ausgang:
[25, 36, 49, 64]
174
Auf diese Weise können wir alle Änderungen an unseren Objekten vornehmen, die in unserem übergeordneten Prozess definiert sind, und die Änderungen, die wir vom untergeordneten Prozess zurückerhalten. Möglich wird dies durch die Shared-Memory-Technik.
Verwenden Sie multiprocessing.Lock()
, um die freigegebenen Ressourcen in Python zu sperren
Wir werden ein entscheidendes Thema namens Schloss
behandeln; Nun, wenn Sie Informatik- oder Betriebssystemkurse besucht haben, haben Sie bereits etwas über das Schloss
gelernt. Allerdings ist die Sperre ein kritischer Begriff, wenn es um multiprocessing
und Betriebssystemkonzepte geht.
Lassen Sie uns zuerst überlegen, warum das Schloss
im wirklichen Leben benötigt wird; In unserem täglichen Leben können einige Ressourcen nicht von zwei Personen gleichzeitig aufgerufen werden.
Zum Beispiel hat die Badezimmertür ein Schloss
, denn wenn zwei Personen gleichzeitig versuchen, darauf zuzugreifen, entsteht eine ziemlich peinliche Situation. Deshalb schützen wir das Badezimmer, eine gemeinsame Ressource mit einem Schloss
.
Ähnlich verhält es sich in der Programmierwelt, wenn zwei Prozesse oder Threads versuchen, auf eine gemeinsam genutzte Ressource zuzugreifen, z. B. eine gemeinsam genutzte Speicherdatei oder eine Datenbank. Dies kann zu Problemen führen, daher müssen Sie diesen Zugriff mit einer Sperre
schützen.
Was passiert, wenn wir diesen Schutz nicht zu unserem Programm hinzufügen, werden wir anhand eines Beispiels sehen. Auch dies ist ein Banking-Softwareprogramm, und hier haben wir zwei Prozesse.
Der erste Prozess ist die Einzahlung von Geld in eine Bank mit der Funktion MONEY_DP()
und der zweite das Abheben von Geld von der Bank mit der Funktion MONEY_WD()
. Und am Ende drucken wir die Endbilanz.
Wir beginnen mit einem Guthaben von 200$
im Abschnitt MONEY_DP
. Wir zahlen 100$
ein, wir haben eine for
-Schleife, die wir 100
-mal durchlaufen haben, und bei jeder Iteration werden unserem Bankkonto 01$
hinzugefügt.
In ähnlicher Weise haben wir in der Funktion MONEY_WD
dieselbe Schleife, die 100
Mal wiederholt wird, und jedes Mal wird 1
Dollar von unserem Bankkonto abgezogen.
Beispielcode:
import multiprocessing
import time
def MONEY_DP(B):
for i in range(100):
time.sleep(0.01)
B.value = B.value + 1
def MONEY_WD(B):
for i in range(100):
time.sleep(0.01)
B.value = B.value - 1
Jetzt verwenden wir eine Shared-Memory-Variable namens value
, die wir bereits im vorherigen Abschnitt kennengelernt haben. Dieser multiprocessing
-Wert ist eine gemeinsam genutzte Speicherressource. Sehen wir uns also an, was passiert, wenn wir versuchen, dieses Programm auszuführen.
if __name__ == "__main__":
B = multiprocessing.Value("i", 200)
Deposit = multiprocessing.Process(target=MONEY_DP, args=(B,))
Withdrawl = multiprocessing.Process(target=MONEY_WD, args=(B,))
Deposit.start()
Withdrawl.start()
Deposit.join()
Withdrawl.join()
print(B.value)
Wir werden es mehrmals ausführen, und jedes Mal werden nur andere Werte gedruckt, aber es sollte 200$
drucken.
Ausgang:
# execution 1
205
# execution 2
201
# execution 3
193
Warum passiert das? Dies geschieht hauptsächlich, wenn dieser Prozess versucht, eine Variable namens B.value
im gemeinsamen Speicher zu lesen.
Sagen wir, B.value
hat einen 200$
-Wert, es liest ihn, fügt dann eins hinzu und fügt dasselbe wieder in dieselbe Variable ein.
Da B.value
200$
ist und diese Additionsoperation auf Betriebssystemebene durchführt, werden auf Betriebssystemebene mehrere Fließbandanweisungen ausgeführt.
Wir haben also die Variable 200
gelesen; es wird eins hinzugefügt und weist der Variablen B.value
201
zurück.
Beispielcode:
B.value = B.value + 1
Jetzt, während es dies gleichzeitig tut, wurde diese Anweisung auch in der Funktion MONEY_WD()
ausgeführt.
Beispielcode:
B.value = B.value - 1
Obwohl wir zuerst einzahlen und dann abheben, wird der Prozess, wenn er versucht, B.value
zu lesen, immer noch 200
sein, weil der Einzahlungsprozess nicht auf die ursprüngliche Variable zurückgeschrieben hat.
Anstatt B.value
als 201
innerhalb des MONEY_WD
-Prozesses zu lesen, wird B.value
als 200
gelesen, und nach dem Verringern von 1
wird es 199
haben.
Deshalb bekommen wir inkonsistentes Verhalten. Lassen Sie uns zuerst Lock
verwenden, um den Zugang zu sperren; Jetzt erstellen wir eine Variable namens Lock
und verwenden multiprocessing
-Module, um die Lock
-Klasse zu verwenden.
Beispielcode:
lock = multiprocessing.Lock()
Jetzt übergeben wir diese Sperre
an beide Prozesse und innerhalb beider Prozesse rufen wir lock.acquire()
auf, um eine Sperre
zu setzen, und um dann eine Sperre
freizugeben, rufen wir lock.release()
Funktion.
Diese lock
-Funktionen schützen den Codeabschnitt beim Zugriff auf die gemeinsam genutzte Ressource, den so genannten kritischen Abschnitt.
Beispielcode:
import multiprocessing
import time
def MONEY_DP(B, lock):
for i in range(100):
time.sleep(0.01)
lock.acquire()
B.value = B.value + 1
lock.release()
def MONEY_WD(B, lock):
for i in range(100):
time.sleep(0.01)
lock.acquire()
B.value = B.value - 1
lock.release()
if __name__ == "__main__":
B = multiprocessing.Value("i", 200)
lock = multiprocessing.Lock()
Deposit = multiprocessing.Process(target=MONEY_DP, args=(B, lock))
Withdrawl = multiprocessing.Process(target=MONEY_WD, args=(B, lock))
Deposit.start()
Withdrawl.start()
Deposit.join()
Withdrawl.join()
print(B.value)
Jetzt druckt dieser Code jedes Mal 200
.
Ausgang:
200
PS C:\Users\Dell\Desktop\demo> python -u "c:\Users\Dell\Desktop\demo\demo.py"
200
PS C:\Users\Dell\Desktop\demo> python -u "c:\Users\Dell\Desktop\demo\demo.py"
200
Hello! I am Salman Bin Mehmood(Baum), a software developer and I help organizations, address complex problems. My expertise lies within back-end, data science and machine learning. I am a lifelong learner, currently working on metaverse, and enrolled in a course building an AI application with python. I love solving problems and developing bug-free software for people. I write content related to python and hot Technologies.
LinkedInVerwandter Artikel - Python Error
- Adresse wird bereits verwendet Fehler in Python
- AttributeError: __Exit__ in Python
- AttributeError: 'Dict'-Objekt hat kein Attribut 'Append' in Python
- AttributeError: 'NoneType'-Objekt hat kein Attribut 'Text' in Python
- AttributeError: Int-Objekt hat kein Attribut
- AttributeError: Modul Urllib hat keine Attributanforderung