In diesem Artikel wird zusammengefasst, was Sie über Python Multi-Process gelernt haben.
Wann wird Multi-Prozess verwendet? ⇒ Bei der Realisierung der Parallelverarbeitung ist es möglich, den Prozess als Mittel zur Realisierung aufzuteilen.
Anwendungen, die CPU-intensive Aufgaben auf einer Multi-Core-CPU ausführen, erfordern derzeit die Verwendung von Multi-Prozessen, um die Multi-Core-CPU nutzen zu können.
https://docs.python.org/ja/3/faq/library.html#can-t-we-get-rid-of-the-global-interpreter-lock
Bevor ich den Quellcode mit mehreren Prozessen erwähne, werde ich erwähnen, wie ein neuer Prozess gestartet wird. In jeder Programmiersprache können Sie einen neuen Prozess starten, indem Sie ein Programm abspalten. In Python wird durch Ausführen von "os.fork ()" jeder Prozess in einem anderen Adressraum ausgeführt, nachdem der Speicherkontext die untergeordneten Prozesse kopiert hat. Unten die Quelle.
fork.py
import os
pid_list = []
def main():
pid_list.append(os.getpid())
child_pid = os.fork()
if child_pid == 0:
pid_list.append(os.getpid())
print()
print("Kind: こんにちは,私はKindプロセスです")
print("Kind:Die PID-Nummer, die ich kenne, ist%s" % pid_list)
else:
pid_list.append(os.getpid())
print()
print("Elternteil:こんにちは,私はElternteilプロセスです")
print("Elternteil:Die PID-Nummer des untergeordneten Prozesses lautet%d"%child_pid)
print("Elternteil:Die PID-Nummer, die ich kenne, ist%s"%pid_list)
if __name__ == "__main__":
main()
$python fork.py
Elternteil:こんにちは,私はElternteilプロセスです
Elternteil:Die PID-Nummer des untergeordneten Prozesses lautet 321
Elternteil:Die PID-Nummer, die ich kenne, ist[320, 320]ist
Kind: こんにちは,私はKindプロセスです
Kind:Die PID-Nummer, die ich kenne, ist[320, 321]ist
Der anfängliche Prozess hat dieselbe PID von 320, aber Sie können sehen, dass der untergeordnete Prozess 321 hinzugefügt hat und dass die beiden Prozesse keinen Speicherkontext gemeinsam nutzen.
Der Prozessspeicher wird standardmäßig nicht gemeinsam genutzt. Wenn Sie zwischen Prozessen kommunizieren möchten, müssen Sie einige Arbeiten ausführen. Um dies zu vereinfachen, bietet das Multiprozessor-Modul verschiedene Möglichkeiten zur Kommunikation zwischen Prozessen. Die folgenden zwei Methoden werden hier vorgestellt.
multiprocessing.Pipe
multiprocessing.sharedctypes
multiprocessing.Pipe
Die Pipe-Klasse hat ein ähnliches Konzept wie Unix- und Linux-Pipes.
multiprocessing.Pipe ()
gibt ein Paar Connection
-Objekte zurück, die beide Enden der Pipe darstellen. Im folgenden Beispiel (pipesample.py) gilt "parent_conn, child_conn = Pipe ()". Die Standardeinstellung "Pipe (True)" macht es bidirektional. Mit "Pipe (False)" ist die Pipe unidirektional, und mit "conn1", "conn2 = Pipe ()" ist "conn1" dem Empfangen von Nachrichten und "conn2" dem Senden gewidmet.
Die Pipe-Klasse sendet und empfängt auch auswählbare Objekte.
Referenz-URL: https://docs.python.org/ja/2.7/library/multiprocessing.html#pipes-and-queues
pipesample.py
from multiprocessing import Process, Pipe
class CustomClass:
pass
def work(connection):
while True:
instance = connection.recv()
if instance:
print("Kind:Erhalten:{}".format(instance))
else:
return
def main():
parent_conn, child_conn = Pipe()
child = Process(target=work, args=(child_conn,))
for item in (
42,
'some string',
{'one':1},
CustomClass(),
None,
):
print("Elternteil:Senden:{}".format(item))
parent_conn.send(item)
child.start()
child.join()
if __name__ == "__main__":
main()
$python pipesample.py
Elternteil:Senden:42
Elternteil:Senden:some string
Elternteil:Senden:{'one': 1}
Elternteil:Senden:<__main__.CustomClass object at 0x7fc785a34ac8>
Elternteil:Senden:None
Kind:Erhalten:42
Kind:Erhalten:some string
Kind:Erhalten:{'one': 1}
Kind:Erhalten:<__main__.CustomClass object at 0x7fc785268978>
Wenn Sie die von "for item in (42, ..., None,):" erstellte Instanz an das Argument "parent.send ()" übergeben, wird der Prozess durch den Empfang von "child .recv ()" gepaart Der Status der Daten wird an übergeben. Sie können auch sehen, dass die Prozessadressen unterschiedlich sind.
multiprocessing.sharedctypes
In der Klasse "multiprocessing.sharedctypes" wird ein gemeinsam genutzter Speicher erstellt und dort werden Datentypen (int type, double type usw.) erstellt.
Bietet eine Möglichkeit zum Einfügen. Der Datentyp folgt C-Typ. Die grundlegendsten sind "Wert (typecode_or_type, * arg, lock = True)" und "Array (typecode_or_type, size_or_initializer, *, lock = True)". typecode_or_type
bestimmt den Typ des zurückgegebenen Objekts. Es handelt sich entweder um einen ctypes-Typ oder einen Ein-Buchstaben-Typcode, wie er im Array-Modul verwendet wird. Da es schwierig ist, Liste, Wörterbuch, Namespace, Sperre usw. zu beschreiben, verwenden Sie in diesem Fall "multiprocessing.Manager".
Referenz: https://docs.python.org/ja/3/library/multiprocessing.html#sharing-state-between-processes
valuearray.py
from multiprocessing import Process, Value, Array
def f(n,a):
n.value = 3.141592
for i in range(len(a)):
a[i] = -a[i]
if __name__ == "__main__":
num = Value('d', 0.0)
arr = Array('i', range(10))
p = Process(target=f, args=(num, arr))
p.start()
p.join()
print(num.value)
print(arr[:])
$python valuearray.py
3.141592
[0, -1, -2, -3, -4, -5, -6, -7, -8, -9]
Die Verwendung von Multi-Prozessen anstelle von Threads erhöht den Overhead erheblich. Die Speichernutzung nimmt zu, insbesondere wenn jeder Prozess einen unabhängigen Speicherkontext hat. Wenn eine große Anzahl von untergeordneten Prozessen generiert wird, ist der schädliche Effekt daher größer als bei der Verarbeitung mit Threads. Für Anwendungen mit mehreren Prozessen ist das Erstellen eines Prozesspools eine gute Möglichkeit, die Ressourcennutzung zu steuern. Die Grundidee eines Prozesspools besteht darin, einen im Voraus festgelegten Prozess vorzubereiten und dann Elemente aus der Warteschlange zu entnehmen und zu verarbeiten. Anstatt den Prozess nach dem Eintreffen der zu verarbeitenden Aufgabe zu starten, starten Sie den Prozess im Voraus, sodass der Prozess unmittelbar nach der Zuweisung der Aufgabe startet.
Pool
KlasseDiese Klasse kümmert sich um die komplizierte Verarbeitung, die mehrere Prozesse verwaltet.
Der folgende Quellcode verwendet die Google Map-API von GCP (Google Cloud Platform), um den Breiten- und Längengrad zu ermitteln, der den Namen der Stadt trifft. Durch Setzen von "POOL_SIZE = 4" werden vier parallel arbeitende Prozesse angegeben. Die Klasse "Pool" kann auch den Kontextmanager verwenden.
geocoding_by_multiprocessing.py
from multiprocessing import Pool
from gmaps import Geocoding
api = Geocoding(api_key='Geheimnis')
PLACES = (
'Reykjavik','Vien','Zadar',
'Venice','Wrocow','Bolognia',
'Berlin','Dehil','New York',
'Osaka'
)
POOL_SIZE = 4
def fetch_place(place):
return api.geocode(place)[0]
def present_result(geocoded):
print("{:s}, {:6.2f}, {:6.2f}".format(
geocoded['formatted_address'],
geocoded['geometry']['location']['lat'],
geocoded['geometry']['location']['lng'],
).encode('utf-8'))
def main():
with Pool(POOL_SIZE) as pool:
results = pool.map(fetch_place, PLACES)
for result in results:
present_result(result)
if __name__ == "__main__":
main()
$ python geocoding_by_multiprocessing.py
b'Reykjav\xc3\xadk, Iceland, 64.15, -21.94'
b'3110 Glendale Blvd, Los Angeles, CA 90039, USA, 34.12, -118.26'
b'Zadar, Croatia, 44.12, 15.23'
b'Venice, Metropolitan City of Venice, Italy, 45.44, 12.32'
b'Wroc\xc5\x82aw, Poland, 51.11, 17.04'
b'Bologna, Metropolitan City of Bologna, Italy, 44.49, 11.34'
b'Berlin, Germany, 52.52, 13.40'
b'Delhi, India, 28.70, 77.10'
b'New York, NY, USA, 40.71, -74.01'
b'Osaka, Japan, 34.69, 135.50'
Das Studium der Parallelverarbeitung ist schwierig. (Lol)
Recommended Posts