Heisenbug?

Fragen zu Tkinter.
Üpsilon
User
Beiträge: 222
Registriert: Samstag 15. September 2012, 19:23

Hallo Alfons, die Probleme mit dem Öffnen des Fensters und der seitlichen Steuerung hab ich beide selbst gefixt bekommen. Das hab ich auch hier bekanntgemacht.

Meine aktuelle Frage ist diese: viewtopic.php?f=18&t=40957#p312752
PS: Die angebotene Summe ist beachtlich.
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

BlackJack hat geschrieben:@Alfons Mittelmeyer: Das macht aber nicht mehr das gleiche weil es 1/FPS Sekunden (+/-) wartet und da die Zeit für die beiden Methodenaufrufe *dazu* kommt. Alles zusammen soll aber maximal 1/FPS-Sekunden dauern.
Das sind Feinheiten, die ich dem Anwender überlasse, man kann ja die Zeit messen und das wieder von der Timerzeit abziehen. Ja mit sleep geht das auch. Und dass es keinen Sinn macht, einen Teil von GUI Verarbeitung in einen extra Thread zu legen, hatte ich auch schon geschrieben. Aber wenn es dem Anwender so Spass macht, kann er ja so etwas probieren.

Ach so, bei der ganzen Sache mit Threadwechsel und pollen kommt noch erschwerend dazu, dass der GUI Thread ja nicht schon wirklich zuende ist, wenn der Python Teil abgearbeitet ist. Tkinter müßte noch hinterher die GUI aufbauen. Und der Threadwechsel in Kombination moi pollen läßt dann tkinter nicht die Zeit dazu. Deshalb ist dann auch nichts zu sehen.
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Und ein weiterer Schwall Unsinn aus der Büchse des Alfons. Threads werden nicht magisch wieder auf LOS! gesetzt, nur weil sie mal unterbrochen wurden. Tkinter käme also sehrwohl an. Wenn es das nicht tut, hat das also andere Gründe. die hat BlackJack ja schon dargelegt. Aber die Macht der Ignoranz ist stärker!!11!1
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

Aber das ist ein lehrreiches Beispiel. Ich hätte auch nicht gedacht, dass ein pollen ohne sleep in einem anderen Thread die GUI gleich so stark lahm legt.
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

__deets__ hat geschrieben:Und ein weiterer Schwall Unsinn aus der Büchse des Alfons. Threads werden nicht magisch wieder auf LOS! gesetzt, nur weil sie mal unterbrochen wurden. Tkinter käme also sehrwohl an. Wenn es das nicht tut, hat das also andere Gründe. die hat BlackJack ja schon dargelegt. Aber die Macht der Ignoranz ist stärker!!11!1
Sorry __deets__ Deine Ignoranz ist unübertrefflich. Dass eine Queue nicht vollaufen kann wenn im Abstand von 1/50 Sekunden etwas hineingeschrieben wird und after mit 1/1000 Sekunden pollt, dürfte wohl klar sein. Außerdem wird nicht nur ein Wert daraus gelesen, sondern alles was drin ist. After 20 würde vollauf für ruckelfrei für das Auge genügen, sofern es nicht Windows ist, denn das ist nicht ruckelfrei zumindest nicht ältere Versionen. Ob Windows10 da besser ist, habe ich nicht ausprobiert.

Also irgendwie hast Du nichts kapiert. BlackJack inzwischen schon.
BlackJack

@Alfons Mittelmeyer: Interessant, denn ich habe es wie __deets__ verstanden. Man kann also das gleiche Verständnis von etwas haben und es gleichzeitig kapiert und nicht kapiert haben. :mrgreen:
Benutzeravatar
kbr
User
Beiträge: 1487
Registriert: Mittwoch 15. Oktober 2008, 09:27

Alfons Mittelmeyer hat geschrieben:Dass eine Queue nicht vollaufen kann wenn im Abstand von 1/50 Sekunden etwas hineingeschrieben wird und after mit 1/1000 Sekunden pollt, dürfte wohl klar sein
After bedeutet ja nur, dass eine Funktion nach der gegebenen Zeitspanne nach dem Aufruf von after aufgerufen wird. Eine Aussage über die Laufzeit eben jener Funktion ist damit nicht gegeben. Insofern muss obige Behauptung nicht zutreffen.
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Alfons Mittelmeyer hat geschrieben:Ach so, bei der ganzen Sache mit Threadwechsel und pollen kommt noch erschwerend dazu, dass der GUI Thread ja nicht schon wirklich zuende ist, wenn der Python Teil abgearbeitet ist. Tkinter müßte noch hinterher die GUI aufbauen. Und der Threadwechsel in Kombination moi pollen läßt dann tkinter nicht die Zeit dazu. Deshalb ist dann auch nichts zu sehen.
Das ist deine Behauptung, und das ist hanebüchener Unfug. Das hat mit Queues und deren Füllstand nix zu tun.
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

BlackJack hat geschrieben:@Alfons Mittelmeyer: Interessant, denn ich habe es wie __deets__ verstanden. Man kann also das gleiche Verständnis von etwas haben und es gleichzeitig kapiert und nicht kapiert haben. :mrgreen:
Es ist eben so, dass viele glauben, sie wüßten, wie etwas ist.
Dann gibt es manche, die sind überzeugt, dass sie recht haben.
Und einige gibt es auch, die absolut nicht einsehen wollen, dass die unrecht haben.

Ich habe mal ein halbes Jahr intensiv Multitasking und Thread Programmierung gemacht. Daher weiß ich es.

Dabei mußten auch Zeiten eingehalten werden. Das wurde so gelöst, dass man in kleineren Intervallen die Zeit gemessen hatte und dann wieder mit sleep eine kleinere Zeit gewartet hatte.

Das geht dann auch:

Code: Alles auswählen

    def hauptschleife(self):
        zeit = time()
        while self.spiel_laeuft:
            while time()-zeit < 1/FPS:
                sleep(0.001) # statt pass
            zeit += 1/FPS
            self.schritt()
            self.ausgabe()
Ich würde sagen, das sleep besser ist als print, oder?

Sehr genau wird das leider auch nicht, da man mit Python nicht in den Mikrosekundenbereich gehen kann.

Nein so war es nicht ganz genau. Sondern man hatte ein Event erwartet, und da durfte man nicht ewig warten, sondern wartete ob das Limit für das Event überschritten war und das war dann ein Fehler, der in die Logdatei einzutragen war.
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Alfons Mittelmeyer hat geschrieben: Es ist eben so, dass viele glauben, sie wüßten, wie etwas ist.
Dann gibt es manche, die sind überzeugt, dass sie recht haben.
Und einige gibt es auch, die absolut nicht einsehen wollen, dass die unrecht haben.

Ich habe mal ein halbes Jahr intensiv Multitasking und Thread Programmierung gemacht. Daher weiß ich es.
Du weißt, das mehrere Threads vom selben Kern ausgeführt werden. Du weißt, das Linux GUI auf einem anderen Kern ausgeführt wird wird. Und das Tkinter's C-Code nicht dran kommt, weil ein anderer Thread läuft.

All diese "Wissen" ist belegbar falsch. Deine drei Punkte oben treffen also zuerstmal auf dich selbst zu. :lol: :lol: :lol:
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

__deets__ hat geschrieben:All diese "Wissen" ist belegbar falsch. Deine drei Punkte oben treffen also zuerstmal auf dich selbst zu. :lol: :lol: :lol:
Du gehörst ganz sicher zu den Unbelehrbaren, da auch dann noch glauben, dass sie recht haben, wenn einwandfrei bewiesen ist, dass sie unrecht haben.

Und ein einwandfreier Beleg ist dieses Programm. Ich habe einen Raspberry Pi3 mit Linux und habe das print('x') rausgemacht.

Und was glaubst Du was kommt, wenn ich statt dem sleep das pass nehme?

Code: Alles auswählen

    def hauptschleife(self):
        zeit = time()
        while self.spiel_laeuft:
            while time()-zeit < 1/FPS:
                sleep(0.001) # statt pass
                #pass
            zeit += 1/FPS
            self.schritt()
            self.ausgabe()
Überhaupt keine GUI. Es gibt Betriebssysteme, welche gar keine Zeitscheibentechnik benützen, sondern erst einen Threadwechsel durchführen, wenn man ihn gestattet, etwa durch sleep. Bei einigen Windowsversionen weiß ich, dass das so war. Daß es allerdings bei meinem Raspberry auch so ist, hat mich doch überrascht. Hätte dieses Linux für besser gehalten. Oder liegt es an Python? Dafür bist ja Du anscheinenend nicht der Spezialist!

Ich würde mal denken, dass es nicht am Betriebssystem liegen sollte, ein Thread ist eben mal kein anderer Prozess. Und Python benutzt anscheinend keine Zeitscheibentechnik.
Zuletzt geändert von Alfons Mittelmeyer am Sonntag 30. Juli 2017, 22:17, insgesamt 1-mal geändert.
Sirius3
User
Beiträge: 17757
Registriert: Sonntag 21. Oktober 2012, 17:20

@Alfons Mittelmeyer: ich habe mal ein halbes Jahr lang intensiv Vögel beobachtet. Fliegen kann ich aber immer noch nicht.

Wenn es das System unterstützt, mißt Python bei sleep Mikrosekunden. Also auch wieder falsch geraten. Korrekterweise sieht die Schleife damit so aus:

Code: Alles auswählen

    def hauptschleife(self):
        start = time()
        for frame in count():
            sleep(max(0, start + frame / FPS - time.time()))
            self.schritt()
            self.ausgabe()
UPS: der Raspberry Pi3 hat einen Quad-Core Prozessor. Da scheint aber einer ganz schön viel Ahnung von Multiprocessing zu haben.
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

Sirius3 hat geschrieben: Wenn es das System unterstützt, mißt Python bei sleep Mikrosekunden. Also auch wieder falsch geraten. Korrekterweise sieht die Schleife damit so aus.
Also, das eine war Meßgenauigkeit. Python mag zwar eine Zeitmessung auf 1/10 Mikrosekunden angeben, aber die Zeitmessung alleine dauert bei meinem Raspberry Pi3 bereits etwa 5 Mikrosekunden.

So ein Ausdruck: a = zeit + 1/FPS
braucht bereits 10 Mikrosekunden.

Also Mikrosekundengenaue Zeitmessungen mit noch ein paar Statements hinzu kann man vergessen. (Und so etwas auch, dass nämlich ein Thread nur maximal 2 Mikrosekunden dauern darf - ein Beispiel aus Mobilfunk Software Anforderungen)

Aber darum geht es ja nicht. Was man bei sleep übergibt ist an sich egal. Hauptsache man ermöglicht einen Threadwechsel. Und der geht auch mit sleep(0)

Auch das kann man tun:

Code: Alles auswählen

    def hauptschleife(self):
        zeit = time()
        while self.spiel_laeuft:
            while time()-zeit < 1/FPS:
                sleep(0)
                #pass
            zeit += 1/FPS
            self.schritt()
            self.ausgabe()
Und wieviel Prozessorkerne der Pi3 hat, davon war nirgendwo die Rede. Die Rede war von Python Threads. Und vier Prozessorkerne ändern auch nichts daran, wie Python seine Threads abarbeitet.

Und zur Genauigkeit der Zeitmessung hier: wenn ein anderer Thread 1/10 Sekunde braucht, hat man mit seiner 1/50 Sekunde eben Pech gehabt.
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Alfons Mittelmeyer hat geschrieben: Überhaupt keine GUI. Es gibt Betriebssysteme, welche gar keine Zeitscheibentechnik benützen, sondern erst einen Threadwechsel durchführen, wenn man ihn gestattet, etwa durch sleep. Bei einigen Windowsversionen weiß ich, dass das so war. Daß es allerdings bei meinem Raspberry auch so ist, hat mich doch überrascht. Hätte dieses Linux für besser gehalten. Oder liegt es an Python? Dafür bist ja Du anscheinenend nicht der Spezialist!

Ich würde mal denken, dass es nicht am Betriebssystem liegen sollte, ein Thread ist eben mal kein anderer Prozess. Und Python benutzt anscheinend keine Zeitscheibentechnik.
Wie immer, viel Geschwaetz, keine Substanz.

Man muss ueber solche Sachen nicht spekulieren, das kann man wissen. Preemptives Scheduling ist seit NT in Windows kein Thema mehr, in Linux war es das noch nie. Und was Python benutzt muss man auch nicht raten, das kann man wissen, wenn man einfach mal in die Sourcen schaut: https://github.com/python/cpython/blob/ ... ead.h#L165

Sind halt POSIX-threads, wie von mir auch schon erwaehnt. "Oder liegt es an Python" ist vom selbsternannten Threading-Experten also ein etwas sehr erbaermliches Zeugnis.

Und dein Code-Beispiel enthaelt noch nicht mal GUI-Code, womit die Frage was du da verbockt hast oder nicht leider unbeantwortbar bleibt.

Folgender Code zeigt wider deiner Behauptung eine voellig responsive GUI auf einem Mehrkern-System, bei 100% CPU-Last auf einem Kern:

Code: Alles auswählen

import tkinter as tk
import threading


def spinner():
    while True:
        pass


def main():
    root = tk.Tk()
    frame = tk.Frame(root)
    frame.pack()
    button = tk.Button(
        frame,
        text="print", fg="red",
        command=lambda: print("foobar")
    )
    button.pack(side=tk.LEFT)
    t = threading.Thread(target=spinner)
    t.start()
    root.mainloop()

if __name__ == '__main__':
    main()
Bleibt also dabei: du redest viel, aber hauptsaechlich Unsinn....
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

__deets__ hat geschrieben:[Man muss ueber solche Sachen nicht spekulieren, das kann man wissen. Preemptives Scheduling ist seit NT in Windows kein Thema mehr, in Linux war es das noch nie. Und was Python benutzt muss man auch nicht raten, das kann man wissen, wenn man einfach mal in die Sourcen schaut: https://github.com/python/cpython/blob/ ... ead.h#L165

Sind halt POSIX-threads, wie von mir auch schon erwaehnt. "Oder liegt es an Python" ist vom selbsternannten Threading-Experten also ein etwas sehr erbaermliches Zeugnis.

Und dein Code-Beispiel enthaelt noch nicht mal GUI-Code, womit die Frage was du da verbockt hast oder nicht leider unbeantwortbar bleibt.

Folgender Code zeigt wider deiner Behauptung eine voellig responsive GUI auf einem Mehrkern-System, bei 100% CPU-Last auf einem Kern:

Bleibt also dabei: du redest viel, aber hauptsaechlich Unsinn....
Anscheinend hast Du null Ahnung von Unterschieden zwischen Multiprozessing, Multitasking und Multithreading und im Sourcecode stand nichts von Zeitscheibentechnik oder gar auf Prozessorkerne aufteilen. Die Threads laufen im selben Prozess wie Python auch und da ist nichts mit Multiprozessing auf Betriebssystemebene in Verbindung mit Threads.

Wenn Du Dir Wissen erwerben möchtest, wie Threads in Python arbeiten, dann findest Du hier eine kurze Einführung:
Siehe: https://www.slideshare.net/dabeaz/an-in ... oncurrency

Und Deine Witz Gui mit einem Button kannst Du als Widerlegung vergessen. Ja man kann den Button sogar noch mit after blinken lassen. Aber für den Canvas mit den movenden Balken und dem Ball reicht es nicht. Alles kommt an, kommt über die Queue die tkinter Commandos werden aufgerufen, aber tkinter hat keine Zeit für den Bildaufbau und damit geht dann nicht einmal mehr der Mausbutton Klick auf den Canvas.

Und dass ich keinen Code gezeigt hätte, stimmt nicht. Es ist genau der Code aus dem Eröffnungspost. Mit einem zusätzlichen sleep(0) geht das, weil damit der GIL (Globaler Interpreter Lock) freigegeben wird und damit kann wieder tkinter drankommen. Aber besser finde ich einen Timer statt Thread und Schleife mit sleep.
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Alfons Mittelmeyer hat geschrieben: Anscheinend hast Du null Ahnung von Unterschieden zwischen Multiprozessing, Multitasking und Multithreading und im Sourcecode stand nichts von Zeitscheibentechnik oder gar auf Prozessorkerne aufteilen. Die Threads laufen im selben Prozess wie Python auch und da ist nichts mit Multiprozessing auf Betriebssystemebene in Verbindung mit Threads.
Ich habe dir die Codezeile aus dem Python Interpreter gezeigt, der die Thread-Implementierung darstellt. Der geneigte Leser entnimmt dem, dass es sich um einen POSIX thread handelt, welcher sehrwohl "multiprozessing" wie du es so schoen falsch ausdrueckst betreibt. Du bleibst ahnungslos...
Alfons Mittelmeyer hat geschrieben: Und dass ich keinen Code gezeigt hätte, stimmt nicht. Es ist genau der Code aus dem Eröffnungspost. Mit einem zusätzlichen sleep(0) geht das, weil damit der GIL (Globaler Interpreter Lock) freigegeben wird und damit kann wieder tkinter drankommen. Aber besser finde ich einen Timer statt Thread und Schleife mit sleep.
Von dir selbst zusammengeklumpter Code den du irgendwo auf deiner Platte hast - der hat halt alle Moeglichen Fehler & taugt darum genau gar nix als "Beleg". Wo du deine kleine Endlosschleife eingebaut hast, kann hier keiner nachvollziehen....

Und "besser finde ich Timer", bei dem du jedes mal einen neuen Thread erzeugst (mit X system-calls), nur um am Ende nichts anderes als zu schlafen ... weiterer Beleg fuer Expertentum vom feinsten :mrgreen: :mrgreen: :mrgreen:
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

__deets__ hat geschrieben: Von dir selbst zusammengeklumpter Code den du irgendwo auf deiner Platte hast - der hat halt alle Moeglichen Fehler & taugt darum genau gar nix als "Beleg". Wo du deine kleine Endlosschleife eingebaut hast, kann hier keiner nachvollziehen....
Wir reden hier übder den Code vom User Üpsilon, falls Du das nocht nicht gemerkt haben solltest, und der steht hier:
viewtopic.php?f=18&t=40957

Oder hast Du das auch noch nicht geschnallt?
__deets__ hat geschrieben: Und "besser finde ich Timer", bei dem du jedes mal einen neuen Thread erzeugst (mit X system-calls), nur um am Ende nichts anderes als zu schlafen ... weiterer Beleg fuer Expertentum vom feinsten :mrgreen: :mrgreen: :mrgreen:
Ach so, jedes Mal ein neuer Thread. Ist da viel Unterschied, ob man den alten Thread in der Thread Queue drin läßt, oder ihn rauswirft (beendet) und wieder über einen Timer reinhängt?
__deets__
User
Beiträge: 14545
Registriert: Mittwoch 14. Oktober 2015, 14:29

Alfons Mittelmeyer hat geschrieben: Wir reden hier übder den Code vom User Üpsilon, falls Du das nocht nicht gemerkt haben solltest, und der steht hier:
viewtopic.php?f=18&t=40957
Oder hast Du das auch noch nicht geschnallt?
Noe. Darueber reden wir nicht. Wir reden ueber irgendwelchen Klumpatsch, der auf deinem Rechner laeuft. Welche beliebigen Fehler du beim rauskopieren und rumfuhrwerken (GUI-Designer angeworfen?) gemacht hast, mag ich mir noch nicht mal in meinen kuehnsten Traeumen ausmahlen.

Abgesehen davon ist das fuer die Widerlegung deiner Behauptung nicht notwendig: mein Code reicht um zu zeigen, dass deine Theorie vom nur durch sleep(..) freizugebenden GIL Unfug ist. Das wuerde dann schon bei meinem Minimalbeispiel nicht klappen. Tut's aber, der Fehler liegt also bei dir - wo auch immer...
Alfons Mittelmeyer hat geschrieben: Ach so, jedes Mal ein neuer Thread. Ist da viel Unterschied, ob man den alten Thread in der Thread Queue drin läßt, oder ihn rauswirft (beendet) und wieder über einen Timer reinhängt?
Lass mich mal kurz ueberlegen... ein Systemaufruf (select mit timeout) https://github.com/python/cpython/blob/ ... le.c#L1444

vs einen neuen Thread anlegen (pthread_create), ein Condition-Objekt erzeugen, das hat ein Lock, etc etc etc... da kommen vielleicht ein dutzend teilweise recht komplexen Systemcalls zusammen, mit Resourcen-Anforderderungen diverser Natur.

Ja. Ist viel mehr Code. Ist deutlich mehr Aufwand. Bringt genau gar nix (fuer diesen Use-case). Aber du darfst das gefuehlt natuerlich besser finden, ist ja wichtig, das man sich im Recht *fuehlt*, nicht, das man es ist... QED dieser Thread (no pun intended).
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

__deets__ hat geschrieben: Abgesehen davon ist das fuer die Widerlegung deiner Behauptung nicht notwendig: mein Code reicht um zu zeigen, dass deine Theorie vom nur durch sleep(..) freizugebenden GIL Unfug ist. Das wuerde dann schon bei meinem Minimalbeispiel nicht klappen. Tut's aber, der Fehler liegt also bei dir - wo auch immer...
Sorry, dass ich das nicht bis in das Detail behandelt hatte, 'nur' durch sleep stimmt natürlich nicht. Es gibt auch Events und eine Event Queue und Events, wie binding an einen command und timer wie after werden natürlich behandelt. Hatte ja geschrieben, dass das mit 'after' und Abholen von der Queue klappt. Nur die Nachbearbeitung des Bildaufbaus durch tkinter also nach der Ausführung des Python codes, die klappt dann nicht mehr. Also nochmals- die Events werden abgearbeitet, nur nachdem der Python Code des Events abgearbeitet ist, ist Sense und tkinter kann den Bildaufbau nicht mehr machen. Endlich kapiert??? Also: Python meldet, der event ist fertig - doch tkinter ist noch nicht fertig, das ist das Problem hier.
Alfons Mittelmeyer hat geschrieben: Ach so, jedes Mal ein neuer Thread. Ist da viel Unterschied, ob man den alten Thread in der Thread Queue drin läßt, oder ihn rauswirft (beendet) und wieder über einen Timer reinhängt?
__deets__ hat geschrieben: Lass mich mal kurz ueberlegen... ein Systemaufruf (select mit timeout) https://github.com/python/cpython/blob/ ... le.c#L1444

vs einen neuen Thread anlegen (pthread_create), ein Condition-Objekt erzeugen, das hat ein Lock, etc etc etc... da kommen vielleicht ein dutzend teilweise recht komplexen Systemcalls zusammen, mit Resourcen-Anforderderungen diverser Natur.

Ja. Ist viel mehr Code. Ist deutlich mehr Aufwand. Bringt genau gar nix (fuer diesen Use-case). Aber du darfst das gefuehlt natuerlich besser finden, ist ja wichtig, das man sich im Recht *fuehlt*, nicht, das man es ist... QED dieser Thread (no pun intended).
Ja dieser Timer vom Threading gefällt mir auch nicht. Man sollte da lieber den after Timer von tkinter nehmen. Den kann man über event.set() auch mit anderen Threads verbinden.

Allerdings stellt sich jetzt dann die Frage, wozu ein anderer Thread.

Es gibt zwei grundsätzliche Konzepte:

- Es ist eine tkinter Anwendung: dann hat so ein anderer Thread nichts darin zu suchen und man nimmt einfach after ohne neuen Thread
- Die GUI könnte eine beliebige GUI sein, z.B. tkinter oder auch Qt oder eine andere.

Dann haben aber solche Bindings überhaupt nichts darin zu suchen:

self.screen.window.bind('<1>', self.on_L)

Außerdem diese locks sind völlig unsinnig:

Code: Alles auswählen

    def on_L(self, e):
        self.gedrueckt_lock.acquire()
        self.gedrueckt = -1
        self.gedrueckt_lock.release()
Außer dem Mousebutton 1 ruft das niemand auf.

Genauso ist dieser Lock völlig unsinnig:

Code: Alles auswählen

    def schritt(self):
        # Ball seitwärts
        self.gedrueckt_lock.acquire()
Außer in hauptschleife wird das nirgendwo anders aufgerufen.

Da das so ein Mischmasch ohne klares Konzept ist - und zudem mit nicht funktionierenden locks, ist zu empfehlen, den Thread ganz rauszuwerfen:

Code: Alles auswählen

    '''
    def hauptschleife(self):
        zeit = time()
        while self.spiel_laeuft:
            while time()-zeit < 1/FPS:
                sleep(0)
                #pass
            zeit += 1/FPS
            self.schritt()
            self.ausgabe()
    '''

    def hauptschleife(self):
        self.screen.window.after(int(1000/FPS),self.hauptschleife)
        self.schritt()
        self.ausgabe()

rr = Rapid_Roll()
#Thread(target=rr.hauptschleife).start()
rr.hauptschleife()
rr.screen.mainloop()
Das hätte dann auch die beste Performance.
Auch after(1,...) in canvas_screen.py macht keinen Sinn. Für Werte unter 10 gibt es nicht den geringsten Grund.
Sirius3
User
Beiträge: 17757
Registriert: Sonntag 21. Oktober 2012, 17:20

@Alfons Mittelmeyer: jetzt hast Du den endgültigen Beweis geliefert, dass Du von Parallel-Programmierung keine Ahnung hast. Locks sind immer dann nötig, wenn mehrere Prozesse/Threads (oder wie Du es auch immer nennen magst; ist im wesentlichen das selbe), auf das selbe Objekt zugreifen, hier `self.gedrueckt`. Wir haben zum einen die Methoden on_xxx, die vom GUI-Thread aus aufgerufen werden, zum anderen `schritt`, das vom Spielupdate-Thread aus aufgerufen wird. Ohne Lock wäre es möglich, nicht-zulässige Zustände zu erzeugen (der Ball befindet sich außerhalb des Spielfeldes). Wir haben es also hier mit einem typischen Anwendungsfall von Locks zu tun, nach Schulbuch implementiert und völlig korrekt und notwendig.
Antworten