Multiprocessing Aufruf innerhalb einer Klasseninstanz

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Martin1986
User
Beiträge: 11
Registriert: Freitag 4. September 2020, 10:13

Hallo alle zusammen,
ich habe wieder mal ein kleine Frage zur Verwendung der Klasse Pool aus dem multiprocessing-Modul.
Innerhalb einer Klassenmethode instanziiere ich einen Pool() (multiprocessing-Modul), dessen map()-Funktion übergebe ich eine weitere Klassenmethode + Liste (Argumente für die Methode).
Die Methode, welche dann auf unterschiedlichen Prozessen läuft hat nur lesenden Zugriff auf eine Klassenvariable.
Solange ich keine Klassenvariable schreibe sollte alles gut sein?? Oder übersehe ich etwas?
Ich habe ein Minimalbeispiel zum besseren Verständnis mit angehängt .
Das Minimalbeispiel läuft tadellos!

In meiner Literatur wird dieser Fall leider nicht behandelt, daher bin ich mir unsicher auch wenn es tadellos ohne Fehler läuft!
Theoretisch müsste die Poolinstanz die Minimalbeispielinstanz vervielfachen (entsprechend der Anzahl der Prozesse). Jeder Prozess hat also eine eigene Instanz von Minimalbeispiel. Ist das richtig?
Seht ihr bei diesem Vorgehen Probleme?

Vielen Dank schon im Voraus zu euren Meinungen.
Martin

Code: Alles auswählen

import multiprocessing
from multiprocessing import Pool


class Minimalbeispiel:
    def __init__(self):
        self.ergebnis = None
        self.summand1 = 5

    def addiere(self, summand):
        """
        :param int summand:
        :return:
        """
        return self.summand1 + summand

    def startmultiprocessing(self):
        """
        Start mehrerer Prozesse mittels Pool und map() aus multiprocessing-Modul
        """
        p = Pool(processes=multiprocessing.cpu_count())
        summanden = [i for i in range(multiprocessing.cpu_count())]
        self.ergebnis = p.map(self.addiere, summanden)
        p.close()
        print(self.ergebnis)


def main():
    minimal = Minimalbeispiel()
    minimal.startmultiprocessing()


if __name__ == "__main__":
    main()
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Grundsaetzlich hast du recht, jeder Prozess hat seine eigene Instanz, die Zuweisung an self erfolgt also unabhaengig.

Aber im konkreten Fall ist self.ergebnis natuerlich ueberfluessig. Das Ergebnis kann so rein lokal gehalten und ausgegeben werden, es kann per return zurueckgegeben werden. Es an die Instanz zu binden ist eigentlich quatsch.
Benutzeravatar
__blackjack__
User
Beiträge: 13118
Registriert: Samstag 2. Juni 2018, 10:21
Wohnort: 127.0.0.1
Kontaktdaten:

@Martin1986: Statt Klassenvariable meinst Du wohl eher Instanzvariable. Eine Klassenvariable hast Du da ja gar nicht. Das wäre auch nicht schön. 🙂

`Pool`-Objekte sind Kontextmanager, die sollte man mit ``with`` verwenden.

Statt ``[i for i in range(process_count)]`` zu schreiben, hätte man auch einfach `list()` mit dem `range`-Objekt aufrufen können: ``list(range(process_count))``. Und ganz konkret muss man da auch gar keine Liste daraus machen, man kann auch einfach das `range`-Objekt selbst übergeben.

Eine kleine ”Falle” hier ist auch, dass bei dem Beispiel nie alle Prozesse arbeit bekommen, da ohne Angabe einer `chunksize` jeder Prozess vier Werte bekommt. Das heisst bei einem System mit 4 Prozessor(kern)en hat nur einer Arbeit, bei 8 haben zwei davon Arbeit, und so weiter.

Code: Alles auswählen

#!/usr/bin/env python3
import multiprocessing
from multiprocessing import Pool


class Minimalbeispiel:
    def __init__(self):
        self.ergebnis = None
        self.summand1 = 5

    def addiere(self, summand):
        return self.summand1 + summand

    def startmultiprocessing(self):
        """
        Start mehrerer Prozesse mittels Pool und map() aus
        multiprocessing-Modul.
        """
        process_count = multiprocessing.cpu_count()
        with Pool(process_count) as pool:
            summanden = range(process_count)
            self.ergebnis = pool.map(self.addiere, summanden, chunksize=1)


def main():
    minimal = Minimalbeispiel()
    minimal.startmultiprocessing()
    print(minimal.ergebnis)


if __name__ == "__main__":
    main()
„All religions are the same: religion is basically guilt, with different holidays.” — Cathy Ladman
Sirius3
User
Beiträge: 17755
Registriert: Sonntag 21. Oktober 2012, 17:20

Ich halte das Vermischen von Hauptprocess mit den Workerprozessen in einer Klasse für nicht so günstig. Ich würde das aufteilen, wobei hier sowohl die eine, als auch die andere Klasse wenig Sinn machen:

Code: Alles auswählen

#!/usr/bin/env python3
import multiprocessing
from multiprocessing import Pool

class Addierer:
    def __init__(self):
        self.summand1 = 5

    def addiere(self, summand):
        return self.summand1 + summand


class Minimalbeispiel:
    def __init__(self, addierer):
        self.ergebnis = None
        self.addierer = addierer

    def startmultiprocessing(self):
        """
        Start mehrerer Prozesse mittels Pool und map() aus
        multiprocessing-Modul.
        """
        with Pool() as pool:
            process_count = multiprocessing.cpu_count()
            summanden = range(process_count)
            self.ergebnis = pool.map(self.addierer.addiere, summanden, chunksize=1)


def main():
    addierer = Addierer()
    minimal = Minimalbeispiel(addierer)
    minimal.startmultiprocessing()
    print(minimal.ergebnis)


if __name__ == "__main__":
    main()
Martin1986
User
Beiträge: 11
Registriert: Freitag 4. September 2020, 10:13

Ich meine natürlich Instanzvariablen, richtig.
Danke für eure Antworten. Hat mich wieder ein Stück weiter gebracht.
Vg Martin
Antworten