threading ?

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.
Xynon1
User
Beiträge: 1267
Registriert: Mittwoch 15. September 2010, 14:22

Hi,

Ich bräuchte mal wieder Hilfe,
ich habe ein Funktion die sieben mal parallel ausgeführt werden müsste aber unterschiedlich schnell endet,
also am Ende müsste ich auf alle sieben warten
Es handelt sich hierbei um recht kurze Zeitspannen.

Die Funktionen müssen Gleichzeitig ausgeführt werden, da diese der Visualisierung dienen und ich alle gleichzeitig ändern möchte.

Wie ist das am besten zu realisieren ?

Danke schon mal wieder im vorraus.
Traue keinem Computer, den du nicht aus dem Fenster werfen kannst.
Xynon auf GitHub
BlackJack

@Xynon1: Du könntest versuchen Threads zu verwenden, aber bei Visualisierung stellt sich die Frage wie diese passiert. GUI-Toolkits mögen es im Normalfall zum Beispiel nicht, wenn von Anderen als dem Hauptthread auf die GUI zugegriffen wird. Wie man dass dann zusammen bringt, hängt vom GUI-Toolkit ab.

Ansonsten kannst Du auch noch versuchen ohne Threads auszukommen, wenn sich die Funktionen so gestalten lassen, dass sie "schrittweise" arbeiten. Zum Beispiel Generatorfunktionen welche die zu visualisierenden Daten generieren. Da kann man dann alle sieben der Reihe nach abfragen und jeweils ihren nächsten Datenpunkt darstellen.
Xynon1
User
Beiträge: 1267
Registriert: Mittwoch 15. September 2010, 14:22

der generator ist scheint mir eine gute idee.
Sollte bei den geringen Zeitfenstern eigentlich keine Probleme geben.
Traue keinem Computer, den du nicht aus dem Fenster werfen kannst.
Xynon auf GitHub
Xynon1
User
Beiträge: 1267
Registriert: Mittwoch 15. September 2010, 14:22

Stellt sich mir nur die frage wie kann ich 7 (eventuell auch weniger oder mehr) gleichzitig laufen lassen?
Traue keinem Computer, den du nicht aus dem Fenster werfen kannst.
Xynon auf GitHub
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

Die Frage die du dir stellen musst ist nicht wie du sie gleichzeitig zum laufen bekommst, sondern wie du sie so laufen lässt dass es erscheint sie laufen gleichzeitig ab. Du kannst die Realität ohnehin nicht abbilden, der Trick ist soviel davon abzubilden dass du damit davon kommst.
Darii
User
Beiträge: 1177
Registriert: Donnerstag 29. November 2007, 17:02

Xynon1 hat geschrieben:ich habe ein Funktion die sieben mal parallel ausgeführt werden müsste aber unterschiedlich schnell endet,
also am Ende müsste ich auf alle sieben warten
Richtig, eine andere Wahl hast du nicht, denn
Die Funktionen müssen Gleichzeitig ausgeführt werden, da diese der Visualisierung dienen und ich alle gleichzeitig ändern möchte.
„gleichzeitig“ und „unterschiedlich schnell“ schließen sich nunmal aus.

Also, Berechnungen wie auch immer anstellen und danach in einem einzigen Thread die Visualisierung realisieren. Wie BlackJack schon schrieb sind GUI-Toolkits normalerweise nicht threadsicher.
Xynon1
User
Beiträge: 1267
Registriert: Mittwoch 15. September 2010, 14:22

@DasIch ja, ist mir klar

trotzdem müssen alle sieben Generatoren zeitnahe initialisiert werden (zeitgleich laufen).
Und dann abwechselt mir die Daten geben.

Aber wie rufe ich die Generatoren auf, so das ich immer in der reihenfolge g1, g2, ..., g7, g1, g2, ...
die Daten bekomme ?

@Darii

Es handelt sich um Tkinter
Traue keinem Computer, den du nicht aus dem Fenster werfen kannst.
Xynon auf GitHub
Darii
User
Beiträge: 1177
Registriert: Donnerstag 29. November 2007, 17:02

Xynon1 hat geschrieben:trotzdem müssen alle sieben Generatoren zeitnahe initialisiert werden (zeitgleich laufen).
Und dann abwechselt mir die Daten geben.
Warum müssen sie das? Lohnen sich threads bei dir überhaupt? Python hat den GIL, deswegen laufen Threads prinzipiell sowieso nicht gleichzeitig und extra Prozesse sind teurer als Threads und da deine Funktionen ja schnell sind ist die Frage ob sich das dann immer noch lohnt.
Aber wie rufe ich die Generatoren auf, so das ich immer in der reihenfolge g1, g2, ..., g7, g1, g2, ...
die Daten bekomme ?
Die Frage wurde schon beantwortet. Entweder indem du sie nacheinander aufrufst oder indem du die Threads startest und danach auf alle Threads wartest (mit Thread.join).
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

Xynon1 hat geschrieben:Aber wie rufe ich die Generatoren auf, so das ich immer in der reihenfolge g1, g2, ..., g7, g1, g2, ...
die Daten bekomme ?
Sowas in dieser Richtung(ungestestet):

Code: Alles auswählen

from itertools import cycle
def foo():
    yield 1
    yield 2
    yield 3

generators = [foo() for _ in xrange(7)]
exhausted = 0
for generator in cycle(generators):
    try:
        print generator.next()
    except StopIteration:
        exhausted += 1
        if len(generators) == exhausted:
            break
Xynon1
User
Beiträge: 1267
Registriert: Mittwoch 15. September 2010, 14:22

@Darii
Wenn ich die Treads nutze bräuchte ich ja die generatoren nicht, aber BlackJack schrieb:
BlackJack hat geschrieben:Ansonsten kannst Du auch noch versuchen ohne Threads auszukommen, wenn sich die Funktionen so gestalten lassen, dass sie "schrittweise" arbeiten. Zum Beispiel Generatorfunktionen welche die zu visualisierenden Daten generieren. Da kann man dann alle sieben der Reihe nach abfragen und jeweils ihren nächsten Datenpunkt darstellen.
@DasIch
Danke in itertools hatte ich schon gesucht, aber über cycle bin ich leider nicht sofort gestolpert, werde das gleich mal testen aber das sieht schon mal gut aus
Traue keinem Computer, den du nicht aus dem Fenster werfen kannst.
Xynon auf GitHub
BlackJack

Die Lösung von DasIch dürfte so nicht allgemein funktionieren, weil ein Iterator der "am Ende" ist, *jedesmal* die Ausnahme auslöst, und nicht jeder nur einmal. Wenn "unterschiedlich lang laufen" auch meint, dass die eine unterschiedliche Anzahl von Datenpunkten liefern, dann geht das so nicht. Wenn sie alle gleich viele Datenpunkte liefern, dann kann man sich auf der anderen Seite das Zählen sparen und gleich bei der ersten Ausnahme die Schleife verlassen.

Ich würde da eine Schleife schreiben und jedesmal eine neue Liste aufbauen mit den Generatoren die noch nicht am Ende sind. Wenn die dann leer ist, weiss man das alles fertig ist.
Xynon1
User
Beiträge: 1267
Registriert: Mittwoch 15. September 2010, 14:22

weiß ich - baue ich auch gerade daran - aber mir hat ja vorher jeglicher ansatz gefehlt
Traue keinem Computer, den du nicht aus dem Fenster werfen kannst.
Xynon auf GitHub
Xynon1
User
Beiträge: 1267
Registriert: Mittwoch 15. September 2010, 14:22

So siehts jetzt aus:

Code: Alles auswählen

while len(gens) > 0:
    for index, gen in enumerate(gens):
        if not gen.next():
            del gens[index]
Hinweis: Meine generatoren geben als letztes false zurück nach dem sie die Schleife verlassen haben
Traue keinem Computer, den du nicht aus dem Fenster werfen kannst.
Xynon auf GitHub
BlackJack

@Xynon1: Warum geben die `False` zurück? Das ist nicht die vorgesehene API.

Aus Listen zu löschen, über die man gerade iteriert, funktioniert nicht wie man das möchte, weil der Iterator nichts davon mitgekommt, dass alle folgenden Elemente um eine Position verrutscht sind. Darum habe ich ja auch geschrieben dass ich in der Schleife jeweils eine neue Liste erstellen würde mit den Iteratoren die noch nicht am Ende sind.
Xynon1
User
Beiträge: 1267
Registriert: Mittwoch 15. September 2010, 14:22

ist also Zufall das das jetzt gut ein paar dutzend mal ohne Fehler und zu meiner vollsten Zufriedenheit ging ? :shock:
Traue keinem Computer, den du nicht aus dem Fenster werfen kannst.
Xynon auf GitHub
Xynon1
User
Beiträge: 1267
Registriert: Mittwoch 15. September 2010, 14:22

Ich iteriere ja eigentlich nur mit .next(), und da dies nicht aufgerufen wird, sollte es da nicht egal sein ?

also mein Generator sieht zusammen gefasst so aus:

Code: Alles auswählen

def generator():
    breakpoint = False
    while not breakpoint:
        if ... == ...:
            breakpoint = True
        yield True
    yield False
und das die diese Werte zurück geben ist reiner missbrauch, denn eigentlich brauche ich den generator ja nur um abwechselnt die Funktionen aufzurufen.

Für mich ist das einfach nur das Signal generator läuft noch oder ist zuende.
Ich weiß nicht gerade schick aber bisher ging es ohne Probleme.
Traue keinem Computer, den du nicht aus dem Fenster werfen kannst.
Xynon auf GitHub
BlackJack

@Xynon1: Ja das ist Zufall dass das zu Deiner vollsten Zufriedenheit läuft. Jedesmal wenn Du mit ``del gens[index]`` einen Iterator entfernst wird der Folgende in der Liste beim nächsten Schleifendurchlauf übersprungen. Es geht nicht um das `next()` was Du da aufrufst, sondern dass welches implizit in der ``for``-Schleife steckt.

Wenn gar keine Werte generiert werden, dann würde ich dafür auch keine Generatorfunktion verwenden. Das ist IMHO ähnlicher Missbrauch wie List Comprehensions nur wegen der Seiteneffekte zu verwenden und nicht weil man eine Liste aufbauen möchte.
Xynon1
User
Beiträge: 1267
Registriert: Mittwoch 15. September 2010, 14:22

Tja aber was dann wenn nicht generatoren, und ja es gibt werte aber die werden direkt an die GUI gegeben. War schließlich auch deine idee xD, gut du wusstest nicht das ich diese keine Werte liefern würden.

Ich bin für jeden Vorschlag offen.

Ach und das mit dem überspringen - gibt es eine Möglichkeit den iterator wieder auf start zu setzen, offensichlich nicht, oder ?
Bzw was passiert wenn der der Generator immer neu zugewiesen wird, wird dann die referenz auf den alten gesetzt und würde dort weiter interieren wo der alte aufgehört ha, eigentlich unlogisch da eine neue instanz gebildet werden sollte ? - Ich habe hier wohl eindeutig klärungs bedarf.
Traue keinem Computer, den du nicht aus dem Fenster werfen kannst.
Xynon auf GitHub
BlackJack

@Xynon1: Ich glaube Du hast das Problem nicht verstanden. Wenn Du eine Liste mit sagen wir mal drei Elementen hast, und darüber iterierst und im ersten Schleifendurchgang das erste Element aus der Liste entfernst, dann rücken die anderen beiden Elemente eine Position nach vorne. Und im zweiten Schleifendurchgang bekommst Du dann nicht das zweite, sondern das dritte Element -- denn das ist ja jetzt dort wo das zweite vorher war. Effektiv wird also das zweite Element in der Schleife nicht berücksichtigt.

Meine Idee war, dass die Generatorfunktionen die Werte generieren, die dann in der GUI dargestellt werden. In dem Fall gäbe es ja richtige Werte. Und Logik und GUI wären an der Stelle auch sauber voneinander getrennt.

Wenn man nichts generiert, kann man ja Klassen schreiben bei denen eine Methode immer den nächsten Schritt ausführt und darstellt.

Was meinst Du mit Generator immer wieder neu zuweisen und neuen Instanzen erstellen? Ich meinte sowas hier (ungetestet):

Code: Alles auswählen

    while generators:
        new_generators = list()
        for generator in generators:
            try:
                data = generator.next()
            except StopIteration:
                pass    # Intentionally ignored.
            else:
                new_generators.append(generator)
                # TODO Do something with data.
        generators = new_generators
Darii
User
Beiträge: 1177
Registriert: Donnerstag 29. November 2007, 17:02

Xynon1 hat geschrieben:@Darii
Wenn ich die Treads nutze bräuchte ich ja die generatoren nicht, aber BlackJack schrieb:
Das eine hat mit dem anderen nichts zu tun, du kannst auch mit Threads Generatoren verwenden. Irgendwie verstehe ich nicht, was dein Problem ist.
Antworten