Nun ja, das ist allgemein so üblich, dass derjenige in der Beweispflicht steht, der von der Norm abweichende Thesen aufstelltAlfons Mittelmeyer hat geschrieben:Und schreibt, dass ich es beweisen müsste.
Gui-Anderung einer Eigenschaft in einem anderen Modul
- Hyperion
- Moderator
- Beiträge: 7478
- Registriert: Freitag 4. August 2006, 14:56
- Wohnort: Hamburg
- Kontaktdaten:
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
assert encoding_kapiert
Zumal es hier darum geht das behauptet wird dort würde etwas existieren. Also kann man das ja auch zeigen. Umgekehrt kann ich nicht beweisen das es nicht existiert weil da ja eben nichts ist auf das ich zeigen könnte.
-
- User
- Beiträge: 1715
- Registriert: Freitag 31. Juli 2015, 13:34
@Sirius3 Finde ich gut, dass Du es sachlich angehst. Das wäre aber dann einen eigenen Thread hier wert, nämlich wie sicher ist die Tcl/Tk Event Queue. Es kann ja sein, dass jemand die Maus bewegt, während er sich nicht in der Tcl/Tk Task befindet. Der Maus Handler - in einer anderen Task, und das ist sogar normal - schreibt aber das Maus Event in diese Event Queue. Kann es dann passieren, dass bei Bewegung der Maus oder beim Klicken das System abstürzt, weil wir uns gerade nicht in der Tcl/Tk Task befinden?
Da müßte man sehr in die Implementierungsdetails gehen und diese Event Queue und den Befehl event_generate, den es dann auch in C etwa für den Maus Handler gibt, genauer untersuchen.
Die andere Frage wäre dann auch, was ist mit after? After soll ja nicht die mainloop aufwecken. Was ist, wenn wir etwas während after etwas machen, das etwa <Configure> betrifft. Hat das dann einen Effekt oder nicht?
Also was meinst Du, sollte man besser die Maus nicht klicken, weil das eventuell nicht threadsicher wäre und das System dabei abstürzen könnte? Denn genau darum geht es, ein Event in diese Queue zu schreiben.
Also nach Meinung von einigen sollte man es wohl besser unterlassen, die Maus zu klicken, solange es nicht bewiesen ist, dass das threadsicher ist.
Da müßte man sehr in die Implementierungsdetails gehen und diese Event Queue und den Befehl event_generate, den es dann auch in C etwa für den Maus Handler gibt, genauer untersuchen.
Die andere Frage wäre dann auch, was ist mit after? After soll ja nicht die mainloop aufwecken. Was ist, wenn wir etwas während after etwas machen, das etwa <Configure> betrifft. Hat das dann einen Effekt oder nicht?
Also was meinst Du, sollte man besser die Maus nicht klicken, weil das eventuell nicht threadsicher wäre und das System dabei abstürzen könnte? Denn genau darum geht es, ein Event in diese Queue zu schreiben.
Also nach Meinung von einigen sollte man es wohl besser unterlassen, die Maus zu klicken, solange es nicht bewiesen ist, dass das threadsicher ist.
@Alfons Mittelmeyer: Man muss da eben nicht in die Implementierungsdetails gehen denn die sind nicht die öffentliche Programmierschnittstelle. Das ist ja gerade die wichtige Eigenschaft von Implementierungsdetails, das man sich nicht auf sie verlassen kann und darf. Öffentlich ist die Informationen das man den Tcl-Interpreter nur von einem Thread aus benutzen darf. Damit ist alles gesagt was man wissen muss. Wer es doch tut schreibt Code der funktionieren kann, aber nicht muss, und schlicht und einfach falsch ist.
Edit:Die Ereignisse für Mausklicks werden Tk-intern in diese Queue geschrieben, also innerhalb des Threads in dem die Hauptschleife läuft, womit das sicher ist weil daran nur dieser eine Thread beteiligt ist.
Edit:Die Ereignisse für Mausklicks werden Tk-intern in diese Queue geschrieben, also innerhalb des Threads in dem die Hauptschleife läuft, womit das sicher ist weil daran nur dieser eine Thread beteiligt ist.
-
- User
- Beiträge: 1715
- Registriert: Freitag 31. Juli 2015, 13:34
Bitte erkennen, begreifen, verstehen. Damit man den Tcl-Interpreter in dem richtigen Thread verwendet, schreibt man nur etwas in die Queue von ihm und weckt ihn dadurch auf. Und daher habe ich das mit dem Event genau richtig implementiert.BlackJack hat geschrieben:Öffentlich ist die Informationen das man den Tcl-Interpreter nur von einem Thread aus benutzen darf. Damit ist alles gesagt was man wissen muss. Wer es doch tut schreibt Code der funktionieren kann, aber nicht muss, und schlicht und einfach falsch ist.
Das ist ebenfalls nicht wahr. Das hieße ja, solange Du Dich nicht in dem Thread der Hauptschleife befindest, kannst Du klicken, was Du willst und es passiert nichts. Also kann man tkinter vergessen, weil Du klicken kannst was Du willst, ohne jeden Effekt. Richtig ist, dass man erst etwas in die Queue schreiben muß, um die mainloop aufzuwecken.BlackJack hat geschrieben:Edit:Die Ereignisse für Mausklicks werden Tk-intern in diese Queue geschrieben, also innerhalb des Threads in dem die Hauptschleife läuft, womit das sicher ist weil daran nur dieser eine Thread beteiligt ist.
Und was macht event_generate? Genau dasselbe, was ich bei den anderen Threads getan habe:
Code: Alles auswählen
def send(self,msgid,msgdata=None):
self.Queue.put((msgid,msgdata))
self.event.set()
Statt send, musst Du Dir eben event_generate vorstellen, wenn Du dazu in der Lage bist.
@Alfons Mittelmeyer: Jetzt fängst Du an absoluten Unsinn zu schreiben. Du schreibst etwas in die Queue vom Tcl-Interpreter und weckst dadurch dessen Thread auf? Wieso sollte der denn ”schlafen”? Gewagte Annahme würde ich mal sagen. Fakt ist das die Dokumentation sagt man darf die Funktionen von dem Tcl-Interpreter nur von einem Thread aus benutzen. Du verwendest `event_generate()` aber von einem anderen aus. Also genau falsch implementiert.
Die Erklärung mit den Mausklicks ist auch totaler Unsinn. Wenn die `mainloop()` läuft (und die muss man nicht aufwecken) dann wird darin irgendwo intern dafür gesorgt das die Mausklicks auf dem jeweiligen System als Ereignisse in die Ereigniswarteschlange landen und dann ebenfalls durch die `mainloop()` abgearbeitet werden. Also alles in dem einen Thread in dem die `mainloop()` läuft. Die dazu nicht aufgeweckt werden muss bzw. falls da doch intern eine Benachrichtigung passiert, dann passiert sie eben genau so: intern. Und das kann auch je nach System anders implementiert sein, weil das ja auch davon abhängt wie man an die entsprechenden Systemereignisse heran kommt. Eben Implementierungsdetails.
Die Erklärung mit den Mausklicks ist auch totaler Unsinn. Wenn die `mainloop()` läuft (und die muss man nicht aufwecken) dann wird darin irgendwo intern dafür gesorgt das die Mausklicks auf dem jeweiligen System als Ereignisse in die Ereigniswarteschlange landen und dann ebenfalls durch die `mainloop()` abgearbeitet werden. Also alles in dem einen Thread in dem die `mainloop()` läuft. Die dazu nicht aufgeweckt werden muss bzw. falls da doch intern eine Benachrichtigung passiert, dann passiert sie eben genau so: intern. Und das kann auch je nach System anders implementiert sein, weil das ja auch davon abhängt wie man an die entsprechenden Systemereignisse heran kommt. Eben Implementierungsdetails.
-
- User
- Beiträge: 1715
- Registriert: Freitag 31. Juli 2015, 13:34
Warum er schläft? Weil professionelle Programmierer keinen Unsinn programmieren und nicht so etwas machen, wie in einer Endlosschleife ständig pollen:BlackJack hat geschrieben:Jetzt fängst Du an absoluten Unsinn zu schreiben. Du schreibst etwas in die Queue vom Tcl-Interpreter und weckst dadurch dessen Thread auf? Wieso sollte der denn ”schlafen”? Gewagte Annahme würde ich mal sagen.
Code: Alles auswählen
while True: self.work()
Code: Alles auswählen
while True:
self.event.wait()
while self.work(): pass
Also kapiere das doch endlich einmal: event_generate ist nicht der Tcl-Interpreter sondern 'self.event.set()' (mit vorherigem Schreiben in die threadsichere Queue) womit der Tcl-Interpreter aus dem wait() seines Schlafes erwacht.BlackJack hat geschrieben:Fakt ist das die Dokumentation sagt man darf die Funktionen von dem Tcl-Interpreter nur von einem Thread aus benutzen. Du verwendest `event_generate()` aber von einem anderen aus. Also genau falsch implementiert.
Und der Rest? Wenn Du nicht fähig bist, etwas zu verstehen, dann höre auf ständig damit weiter zu machen.
Manche verstehen eben nur Endlosschleife und pollen, eventuell verlangsamt durch sleep oder after. Und empfehlen pollen in einer Schleife.
Zuletzt geändert von Alfons Mittelmeyer am Donnerstag 3. September 2015, 17:00, insgesamt 2-mal geändert.
@sparrow: Zumindest mit ``del`` hat er für mich eindeutig getrollt. Normalerweise wissen Trolle ja, dass sie Unsinn von sich geben. In diesem Fall war es aber eher eine Art Trollen aus Überzeugung.
Und aktuell ist es eher ein Mischmasch, bei dem Alfons mit seinen 2 Monaten an Python-Erfahrung natürlich stets die klügsten Ideen hat.
Und aktuell ist es eher ein Mischmasch, bei dem Alfons mit seinen 2 Monaten an Python-Erfahrung natürlich stets die klügsten Ideen hat.
@Alfons Mittelmeyer: Du weiss nicht ob der Tcl/Tk-Thread in der Hauptschleife gerade schläft oder nicht und falls er schläft auch nicht ob er durch `event_generate()` aufgeweckt wird oder nicht. Und vor allem kannst Du Dir nicht sicher sein das der Thread gerade in dem Augenblick schläft während Du ein `event_generate()` von einem anderen Thread aus ausführst, denn er kann ja just in dem Augenblick wach sein weil er ein Systemereignis verarbeiten muss, oder irgendetwas anderes was innerhalb des Threads passiert von dem aus legal auf den Tcl-Interpreter zugegriffen werden darf.
Dein `self.event` und Deine Queue haben nichts mit der threadsicherheit des Tcl-Interpreters zu tun. Das Du die Python-Seite von Deiner kaputten Lösung absicherst macht die Gesamtlösung nicht sicher weil `event_generate()` unsicher ist und Du das auch nicht sicher hinbekommst weil Du an die Interna vom Tcl-Interpreter gar nicht heran kommst.
Ich verstehe das der Tcl-Interpreter explizit dokumentiert nicht threadsicher ist, und zwar pauschal wirklich gar nicht, und damit pollen die einzige Möglichkeit ist. Das ist ein Fakt und keine Meinung. Das kannst Du auch nicht mit persönlichen Angriffen wegdiskutieren. Ich verstehe genug vom Programmieren, sowohl vom Studium als auch davor und danach durch langjährige Praxis.
Dein `self.event` und Deine Queue haben nichts mit der threadsicherheit des Tcl-Interpreters zu tun. Das Du die Python-Seite von Deiner kaputten Lösung absicherst macht die Gesamtlösung nicht sicher weil `event_generate()` unsicher ist und Du das auch nicht sicher hinbekommst weil Du an die Interna vom Tcl-Interpreter gar nicht heran kommst.
Ich verstehe das der Tcl-Interpreter explizit dokumentiert nicht threadsicher ist, und zwar pauschal wirklich gar nicht, und damit pollen die einzige Möglichkeit ist. Das ist ein Fakt und keine Meinung. Das kannst Du auch nicht mit persönlichen Angriffen wegdiskutieren. Ich verstehe genug vom Programmieren, sowohl vom Studium als auch davor und danach durch langjährige Praxis.
-
- User
- Beiträge: 1715
- Registriert: Freitag 31. Juli 2015, 13:34
@BlackJack Ich mag nicht mehr, weil es nichts bringt, jemand etwas erklären zu wollen, der es anscheinend nicht begreifen kann. Mein Rat, halte Dich an das, was professionelle Programmierer, wie Guido van Rossum dazu geschrieben haben:
Quelle: http://code.activestate.com/lists/pytho ... cuss/3493/From: Guido van Rossum <gui...@python.org>
Wed, 6 Nov 2013 16:39:16 -0800
Hi Kevin,
Thanks for the clarification.
Fortunately using event_generate() with a virtual event works like a charm
(unlike after() or after_idle()) so I am happy with the way things are now.
It has been quite frustrating though to get here.
--Guido
@Alfons Mittelmeyer: das Problem mit Deinem Mailings-Link ist, dass Du die Zwischentöne nicht mitgelesen hast. Da ist ein Guido van Rossum der aus irgendeinem Grund einmal ein Tk-Programm schreiben wollte, aber bei dessen Umsetzung am Verzweifeln ist. Dann etliche Poster, die irgendwelche Halbwahrheiten aus dem Internet gezogen haben, die beim einen funktionieren, bei anderen wieder nicht. Es gibt keinen Weihnachtsmann und im Internet stehen nicht nur gut recherchierte und wahre Artikel.
-
- User
- Beiträge: 1715
- Registriert: Freitag 31. Juli 2015, 13:34
Etliche Poster, die Halbwahrheiten aus dem Internet beziehen? Das ist eine hochrangige Expertenrunde. Wer ist zum Beispiel Kevin Walzer? Chef Core Entwickler für Tcl/Tk System für Mac OS X. Und solche Experten wissen genau, was Sache ist. Also hört endlich mal mit dem Trollen auf.Sirius3 hat geschrieben:@Alfons Mittelmeyer: das Problem mit Deinem Mailings-Link ist, dass Du die Zwischentöne nicht mitgelesen hast. Da ist ein Guido van Rossum der aus irgendeinem Grund einmal ein Tk-Programm schreiben wollte, aber bei dessen Umsetzung am Verzweifeln ist. Dann etliche Poster, die irgendwelche Halbwahrheiten aus dem Internet gezogen haben, die beim einen funktionieren, bei anderen wieder nicht. Es gibt keinen Weihnachtsmann und im Internet stehen nicht nur gut recherchierte und wahre Artikel.
Und das Problem mit after und after_idle ist, dass man da nicht die mainloop aufweckt, sondern noch zusätzlich die Maus bewegen muss, um dann sporadisch GUI updates zu bekommen. Zumindest gibt es diese Probleme bei manchen Tcl/Tk Versionen und in manchen Fällen.
Ihr wollt doch nicht ernsthaft behaupten, dass Guido van Rossum sich nicht mit Python auskennnt und nur Halbwahrheiten aus dem Internet bezogen hat und bei Kevin Walzer ist es dasselbe in Bezug auf Tcl/Tk?
`event_generate` sollte in CPython threadesafe sein. Der Aufruf wird intern über `tk.call` abgesetzt, welcher hier implementiert ist: https://github.com/python/cpython/blob/ ... er.c#L1509. Der Code unter `#ifdef WITH_THREAD` macht im Prinzip das, was die Tcl-Doku für messaging zwischen Threads vorsieht.
Fraglich ist, ob andere Pythonvarianten das auch umsetzen. Mit PyPy zumindest funktioniert es nicht.
Fraglich ist, ob andere Pythonvarianten das auch umsetzen. Mit PyPy zumindest funktioniert es nicht.
-
- User
- Beiträge: 1715
- Registriert: Freitag 31. Juli 2015, 13:34
@jerch Ich bin mir auch nicht sicher, ob das für alle Python und tkinter Varianten gilt. Jedenfalls braucht BlackJack nicht meinen Code niedermachen. Mein Proxy enthält nämlich gar nichts von event_generate. Und wer diesem Befehl mißtraut, kann ja für Messages, die von außen kommen in seiner Applikation setzen:Und pollen muss man da auch nichts. Und für die internen Messages entweder event_generate oder so lassen, nämlich direkter Funktionsaufruf.
Oder eventuell noch besser, weil es da auch Probleme bei Guido van Rossum gab:Und die internen dann bei direktem Funktionsaufruf belassen.
Kann ja jeder das nehmen, was ihm am sichersten erscheint.
Eines muss allerdings beim Proxy noch ergänzt werden, nämlich die Destroy Methode. Die ist nötig, wenn man wirklich mehre Tasks verwendet:Man muß dann nämlich die beim externen Proxy registrierten Callbacks löschen, wenn man seine Task beendet aber Python nicht. Ansonsten würde das System crashen, wenn noch jemand etwas sendet, aber der Empfänger nicht mehr existiert.
Code: Alles auswählen
proxy.extern_trigger = lambda: root.after(1,proxy.trigger())
Oder eventuell noch besser, weil es da auch Probleme bei Guido van Rossum gab:
Code: Alles auswählen
proxy.extern_trigger = lambda: root.after(1,lambda: root.event_generate("<<SEND>>", when="tail"))
Kann ja jeder das nehmen, was ihm am sichersten erscheint.
Eines muss allerdings beim Proxy noch ergänzt werden, nämlich die Destroy Methode. Die ist nötig, wenn man wirklich mehre Tasks verwendet:
Code: Alles auswählen
def __del__(self): self.extern_proxy.undo_receiveAll(self)
Das ist ja gerade das Problem, dass es verschiedene TkInter-Implementierungen von verschiedenen Python-Versionen auf unterschiedlichen Systemen gibt und man sich nur an das halten darf, was in der Dokumentation dazu steht. after muß vor oder innerhalb des Event-Loops aufgerufen werden, so dass sowohl Vorschlag 1 als auch Vorschlag 2 nicht funktioniert. Und statt __del__ gibt es auch saubere Lösungen.
Ich habe den Eindruck, das mit den Implementierungsdetails ist Alfons völlig egal. Er nimmt es anscheinend in Kauf, dass ihm seine Bibliothek bei der nächsten Python-Version um die Ohren fliegen könnte, falls sich die Python-Entwickler entscheiden, etwas an den Implementierungsdetails zu verändern. Denn bekanntlich nimmt man bei nicht dokumentierten Details oftmals keine Rücksicht auf Abwärtskompatibilität.
Für mich ist diese Denkweise übrigens ein klarer Grund, von der ernsthaften Nutzung seiner Bibliothek abzuraten. Hier wird sich auf undokumentierte und sehr komplexe Details verlassen, ohne dass es irgendeine Art von Hinweis an den Benutzer in Bezug auf diese Risikofreudigkeit gibt. Hier geht es ja um weitaus mehr als ein paar Zeilen Python-Code, die man notfalls selbst schreiben könnte, falls sie mal aus der Standardbibliothek wegfallen oder "ungünstig" verändert werden.
Alfons hat Glück, dass es den Haftungsauschluss gibt, sodass ihn niemand dafür belangen kann, wenn ein Benutzer in gutem Glauben an sein Projekt irgendwann mal gehörig auf die Nase fällt...
Für mich ist diese Denkweise übrigens ein klarer Grund, von der ernsthaften Nutzung seiner Bibliothek abzuraten. Hier wird sich auf undokumentierte und sehr komplexe Details verlassen, ohne dass es irgendeine Art von Hinweis an den Benutzer in Bezug auf diese Risikofreudigkeit gibt. Hier geht es ja um weitaus mehr als ein paar Zeilen Python-Code, die man notfalls selbst schreiben könnte, falls sie mal aus der Standardbibliothek wegfallen oder "ungünstig" verändert werden.
Alfons hat Glück, dass es den Haftungsauschluss gibt, sodass ihn niemand dafür belangen kann, wenn ein Benutzer in gutem Glauben an sein Projekt irgendwann mal gehörig auf die Nase fällt...
-
- User
- Beiträge: 1715
- Registriert: Freitag 31. Juli 2015, 13:34
Vor oder innerhalb des Event-Loops hast Du immer. Und die Callbackfunktion wird dann im Thread der Event-Loop ausgeführt, allerdings nicht unbedingt während des Event-Loops und das ergibt das Problem beim GUI Update. Lösung zwei findet also im richtigen Thread statt, aber nicht unbedingt in der Event-Loop. Zu prüfen wäre, ob das dann ein Problem für event_generate ergibt, wenn man im GUI Thread ist, aber nicht in der Event-Loop. Der Callback für event_generate landet dann jedenfalls in der Event-Loop.Sirius3 hat geschrieben:Das ist ja gerade das Problem, dass es verschiedene TkInter-Implementierungen von verschiedenen Python-Versionen auf unterschiedlichen Systemen gibt und man sich nur an das halten darf, was in der Dokumentation dazu steht. after muß vor oder innerhalb des Event-Loops aufgerufen werden, so dass sowohl Vorschlag 1 als auch Vorschlag 2 nicht funktioniert. Und statt __del__ gibt es auch saubere Lösungen.
Eigentlich sollte man erwarten, dass die Programmierer event_generate besser programmieren oder aber einen ähnlichen Befehl machen, für nur solche virtuellen events. Denn in event_generate ist ja auch hineingepackt, dass man etwa Mausklicks und ähnliches simuliert. Ein einfacherer Befehl für nur solche virtuellen events wäre sicher leicht threadsicher zu implementieren.
-
- User
- Beiträge: 1715
- Registriert: Freitag 31. Juli 2015, 13:34
@snafu Schau Dir meine Proxy an. Ein event_generate ist da nicht drin und somit auch nicht in meiner Bibliothek. Da kann der Programmierer frei einstellen, wie er dann die beiden Trigger proxy.trigger und proxy.extern_trigger setzen möchte. Wenn er nur den Proxy für messages in der GUI Task braucht, dann braucht er gar nichts zu setzen, denn proxy.trigger steht auf direktem Funktionsaufruf und proxy.extern_trigger auf noop(). Also dass externe Messags nur in die Queue gelegt werden ohne trigger. Kann man ja auch mit pollen über proxy.trigger() abholen oder durch senden einer dummy Message, etwa proxy.send('DUMMY'). Wenn man seine GUI Callbacks über proxy.send('execute_function',mycallback) realisisiert, werden die externen Messages spätestens beim nächsten GUI event mit abgeholt. Da könnte man genauso gut ein <B1-Motion> event setzen, denn die Maus wird man schon irgendwann einmal bewegen, oder? Oder hat jemand noch eine Idee ohne pollen. Etwa sonstige GUI events, die sich bestimmt oft ereignen?
Normalerweise wäre zu erwarten, dass jemand der mit der Maus klickt, daraufhin mit ihr noch wackelt. Nur wenn es sich um Anzeigen von einem externen Gerät handelt und man nur gelegentlich auf den Bildschirm schaut, dann bräuchte man dafür den externen Trigger.
after funktioniert unter Windows, hat aber auf dem Mac Probleme.
Also wäre schön, wenn man Lösung zwei überprüfen könnte, ob die problematisch ist.
Und wie gesagt, das hat alles nichts mit dem Code für meinen Proxy zu tun. Man kann von seiner Applikation aus die Trigger umstellen.
Wenn wir keine Universallösung finden, dann muss man eben je nach Umgebung es so machen, dass es entsprechend funktioniert, also für Windows so und Mac eben so. after weckt eben nicht bei jedem System die mainloop auf. Und event_generate funktioniert wohl auch nicht überall. Und Mausbewegung hat man auch nicht in jedem Fall.
Also würde after mit triggern von event_generate überall funktionieren?
Normalerweise wäre zu erwarten, dass jemand der mit der Maus klickt, daraufhin mit ihr noch wackelt. Nur wenn es sich um Anzeigen von einem externen Gerät handelt und man nur gelegentlich auf den Bildschirm schaut, dann bräuchte man dafür den externen Trigger.
after funktioniert unter Windows, hat aber auf dem Mac Probleme.
Also wäre schön, wenn man Lösung zwei überprüfen könnte, ob die problematisch ist.
Und wie gesagt, das hat alles nichts mit dem Code für meinen Proxy zu tun. Man kann von seiner Applikation aus die Trigger umstellen.
Wenn wir keine Universallösung finden, dann muss man eben je nach Umgebung es so machen, dass es entsprechend funktioniert, also für Windows so und Mac eben so. after weckt eben nicht bei jedem System die mainloop auf. Und event_generate funktioniert wohl auch nicht überall. Und Mausbewegung hat man auch nicht in jedem Fall.
Also würde after mit triggern von event_generate überall funktionieren?