Threadprogrammierung mit Variablen

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.
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Mad-Marty hat geschrieben:Warum nicht Queue objekte?
Benutze eben einen thread für die "arbeit" und einen für eingaben.
Dazwischen eine Queue, z.b. "eingabe_queue".
Der worker checkt regelmässig ob in der eingabe queue etwas liegt und reagiert darauf.
Hallo Mad-Marty!

Queue-Objekte sind nicht das Allheilmittel. Sie sind super, wenn ich z.B. einen Thread blockieren lassen möchte, bis ein neuer Wert übergeben wird, oder wenn immer wieder verschiedene Werte von einem Hauptthread übergeben werden müssen.

ABER sie bringen nichts, wenn mehrere Threads "gleichzeitig" mit den selben Werten arbeiten müssen. Z.B. ein Counter. oder bei einem Poker-Spiel die Einsätze der Mitspieler. Man könnte den neuen Einsatz zwar in eine Queue legen, aber dann kann nur ein Thread etwas damit anfangen. --> Genau der Thread, der sich den Wert als Erster aus der Queue holt. Man müsste also immer einen Thread haben, der den Wert wieder verteilt.

Ja, es ist natürlich mit Queues machbar, aber die Frage ist, ob es überhaupt notwendig ist. Genügt es vielleicht schon, von einem Thread aus eine Variable zu setzen, auf die die anderen Threads ebenfalls Zugriff haben? Das macht das Programm nicht so kompliziert wie es z.B. mit Queues sein kann.

Alles was ich hier geschrieben habe gilt nur dann, wenn es kein Problem beim "einfachen" Zugriff auf eine "einfache" Variable (z.B. str oder int) geben kann. Das ist für mich aber im Moment noch nicht bestätigt.

Wenn es aber bestätigt wird, dann spricht nichts gegen den gemeinsamen Zugriff auf eine Variable. Dann muss nur noch die Verwendung des "global"-Statements eingeschränkt werden. Z.B. durch Auslagern der gemeinsam benutzten Werte in eine gemeinsam genutzte Klasseninstanz.

mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Hallo!

Jetzt weiß ich auch wieder, warum ich mir nicht sicher bin, ob der einfache Variablezugriff Schwierigkeiten bereiten kann.

Ich glaube, in folgendem Beispiel gab es Ungereimtheiten (bei der Verwendung mit wxPython), die sich erst legten, als ich die Statusvariable in ein Event umwandelte. (ganz sicher bin ich mir allerdings nicht :oops: )

In diesem Beispiel wird die Methode "stop" von einem anderen Thread aufgerufen.

Code: Alles auswählen

import threading


class HatSchwierigkeitenBereitet(threading.Thread):
    
    def __init__(self):
        threading.Thread.__init__(self)
        self.canceled = False
    
    def run(self):
        while True:
            if self.canceled:
                break
            print "."
    
    def stop(self):
        self.canceled = True


class Funktioniert(threading.Thread):
    
    def __init__(self):
        threading.Thread.__init__(self)
        self.canceled = threading.Event()
    
    def run(self):
        while True:
            if self.canceled.isSet():
                break
            print "."
    
    def stop(self):
        self.canceled.set()


class FunktioniertWahrscheinlichAuch_IstAberEvtNichtNotwendig(threading.Thread):
    
    def __init__(self):
        threading.Thread.__init__(self)
        self.canceled = False
        self.lock = threading.Lock()
    
    def run(self):
        while True:
            self.lock.acquire()
            try:
                if self.canceled:
                    break
            finally:
                self.lock.release()
            print "."
    
    def stop(self):
        self.lock.acquire()
        try:
            self.canceled = True
        finally:
            self.lock.release()
mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

@gerold

Deine letzten beiden Beispiele sind im Prinzip identisch, du hast lediglich "threading.Event" nachgebaut und quasi zur Weitergabe von beliebitgen Objekten erweitert.

Dein erstes Beispiel wird früher oder später Probleme bereiten. Momentan ist es zwar so, dass eine Anweisung, die direkt in Bytecode umgewandelt werden kann nicht unterbrechbar ist (dafür ist der GIL da), aber das wird sicherlich nicht ewig so bleiben. Wenn ich mich richtig erinnere, meine ich schon von einer inoffiziellen Version gehört zu haben, die diese Beschränkung nicht mehr hat (vielleicht kennt ja jemand den Namen).

In deinem Beispiel hingegen hat man neben der Zuweisung auf self.canceled (was glaube ich in eine einzige Bytecode-Anweisung umgesetzt wird) noch die Auflösung von "self". Das scheint zwar noch nicht kritisch zu sein, aber wenn man jedes mal auf so etwas achten muss, geht bei irgend einer Änderung mit Sicherheit etwas schief.
Benutzeravatar
Rebecca
User
Beiträge: 1662
Registriert: Freitag 3. Februar 2006, 12:28
Wohnort: DN, Heimat: HB
Kontaktdaten:

Ich haette jetzt vermutet, dass sich die ersten beiden theoretisch gleich verhalten muessten (mal davon abgesehen, dass etwas anderer Code ausgefuehrt wird, sodass sie sich praktisch doch wieder anders verhalten). Es koennte ein Kontextwechsel zwischen der if-Abfrage und dem break auftreten, sodass die anschliessende print-Ausgabe noch ausgefuehrt wird, wenn self.cancel schon auf True steht. Lediglich das letzte Beispiel verhindert dies, da ein Lock um beide Statements gelegt wird.

Ist natuerlich die Frage, was hier "funktioniert (nicht)" bedeutet.
Miko

wobei meistens braucht man ja nicht eine variable in 2 threads zum schreiben.

und wenn ein thread schreibt und einer liest dürfts doch keine probleme geben oder?

Dinge wie lock und queue kenn ich noch nicht deswegen blick ich da noch nicht ganz durch.
Ich benutze auch immer das Modul Thread und nicht threading!

Aber danke für die zahlreichen antworten
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Miko hat geschrieben:und wenn ein thread schreibt und einer liest dürfts doch keine probleme geben oder?
Doch, die gibt es. Irgendwo in diesem Thread ist schon der Begriff "Race Condition" gefallen, such einfach mal danach.
Miko

Sorry ich kann mit dem Begriff nichts anfangen.
EyDu
User
Beiträge: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Miko hat geschrieben:Sorry ich kann mit dem Begriff nichts anfangen.
Sind Wikipedia und Google wirklich so schwer zu bedienen...?
Miko

ich bin ja großer fan von sufus und suchmaschinen.
aber wozu sind dann solche foren da?
Ich kann alles bei google eintippen warum gibts dann python-forum.de?

In den letzten Jahren hat es sich wirklich dazu entwickelt dass solche foren nicht mehr als Plattform dienen sein wissen zu teilen sondern mehr als chatplatform für stammgäste und wenn jemand anderes mal was postet wird das ausgeschlachtet und geschrieben "Sufu benutzen".

Dann sollte das forum vielleicht besser geschlossen werden und ein text erscheinen "Bitte google benutzen"
BlackJack

Da tust Du diesem Forum unrecht. Ein einfaches "Ist Google heute kaputt" oder "RTFM" kommt hier *sehr* selten als Antwort.

Leonidas hat in Dir *in diesem Thread* erklärt was eine "race condition" ist. Und Rebecca hat gleich im nächsten Beitrag noch ein einfacheres, verständlicheres Beispiel dafür nachgeschoben.
Benutzeravatar
Rebecca
User
Beiträge: 1662
Registriert: Freitag 3. Februar 2006, 12:28
Wohnort: DN, Heimat: HB
Kontaktdaten:

Miko hat geschrieben:aber wozu sind dann solche foren da?
Um dir bei Problemen zu helfen, die du nicht mit Hilfe von $SUCHMASCHINE loesen kannst.

Sieh es doch mal so: Warum sollte jemand n Minuten seiner Zeit opfern, um hier etwas zu schreiben, was sowieso schon viel besser bei Wikipedia oder woanders steht?
Miko

klar rebecca seh ich auch so. Aber nahezu alles lässt sich irgendwo im internet finden. somit müsste man mindestens 95 % der Threads in diesem Forum hier löschen. Weil irgendwo stehts immer!

Oh stimmt, Leonidas hats erklärt. Hab den Begriff der mir fremd war wahrscheinlich überlesen oder nicht behalten.
Benutzeravatar
Sr4l
User
Beiträge: 1091
Registriert: Donnerstag 28. Dezember 2006, 20:02
Wohnort: Kassel
Kontaktdaten:

Du hast den Wert 95% ind en Raum gewurfen ;-)

Dann behaupte ich mal 95% der Suchanfragen zum Thema Python mit deutscher Fragestellung führen in dieses Forum ;-)

Ich finde das Thema ja hochinteressant muss ich sagen also mal ne kleine zwischen Frage von mir) :

man kann doch das verändern von variablen einem eigenen thread als aufgabe geben. und mit do = 1 wird gesetzt wenn der thread etwas tut ersrt wenn do wieder auf 0 gestezte wird ( nach abschluss der aufgabe ) kann der thread neue aufgaben annehmen.
dadurch kann kein gleichzeitiges aändern vorkommen. vll kann man auch befehle in eine warteschlange packen und nach der ausführung löschen. diese warteschlange muss dann jedoch nach eingangsreihenfolge abgearbeitet werden.
Miko

@ Sr4l:
Dabei umgehst du aber das Problem wieder nicht. Laut den obigen Aussagen wechselt der Prozessor so häufig und schnell zwischen den Threads, dass do noch nicht im Arbeitsspeicher auf 1 gesetzt ist aber der 2te Thread schon anfange will die Variable zu ändern. Und dann ändern wieder beide Threads die Variable und einer überschreibt das Ergebniss des anderen (was noch aktzeptabel wär) oder das Programm stürzt ab.
Benutzeravatar
smuerf
User
Beiträge: 3
Registriert: Donnerstag 29. November 2007, 11:08
Wohnort: Chemnitz

Weil hier ja allerhand Spekulationen zu gemeinsam genutzten Datenstrukturen ausgetauscht werden und da doch einiges nicht so klar zu sein scheint, hier meine Einschätzung:
Mit Threads handelt man sich leicht Inkonsistenzen ein!!! vor allem wenn man gemeinsam genutzte Variablen verwendet. Aber gerade das ist ja der Vorteil von Thraeds gegenüber zum Beispiel Prozessen. Man kann gemeinsame Variablen nutzen, das ist schnell und spart Speicherplatz!
Jetzt kommt der Haken: Man muss die gemeinsamen Variablen natürlich aber vor (pseudo)gleichzeitigem Schreibzugriff sichern! Das macht man mit Locks. Soweit sogut :)
Jetzt muss man für sich selbst entscheiden wie gut man sich mit (Pseudo)Parallelität auskennt. Wer sich nicht gut auskennt sollte auf Datenstrukturen, die erprobt und verifiziert sind, zurückgreifen und darüber, und nur darüber, auf seine gemeinsamen Variablen zugreifen! Wer meint es besser zu wissen kann natürlich versuchen ein wenig mehr Performance durch selbst verwaltete Locks aus dem Programm herauszuholen. Aber Vorsicht, wie schon erwähnt, wenn das Programm nur lange genug läuft und es kommt zu einer sogenannten "write violation" Schreibzugriffs-Inkonsistenz, ist das ganze Ergebnis des Programms womöglich nicht mehr brauchbar. Das nützt dann erst recht keinem was.

Also entscheide dich: Willst du mit wenig Aufwand ein Programm, was definitiv funktioniert, dann nutzte erprobte Datenstrukturen! Willst du etwas mehr Performace, dann investiere viel Zeit und schreibe dir deine eigenen Strukturen!

Ich hoffe ich habe das klargestellt :D
Angenommen wir würfeln das Ergebnis aus:
Welche Güte können wir dabei erreichen? ;-)
Antworten