'command' zwei Argumente übergeben?

Fragen zu Tkinter.
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

Eine Zeile Text ausgeben mit verschiedenen Funktionen: Crash nach 796067 Funktionen.
Schon ganz beachtlich
BlackJack

@Alfons Mittelmeyer: Also einen Crash programmiere ich Dir in einer Funktion. Da 796.067 zu benötigen ist hochgradig ineffizient. ;-)

PS: Und selbst das bekommst Du nicht konkret hin, sondern nur als Behauptung. Sehr schwach…
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

BlackJack hat geschrieben:@Alfons Mittelmeyer: Also einen Crash programmiere ich Dir in einer Funktion. Da 796.067 zu benötigen ist hochgradig ineffizient. ;-)

PS: Und selbst das bekommst Du nicht konkret hin, sondern nur als Behauptung. Sehr schwach…
Was Du schreibst ist sehr schwach. Es geht nicht darum Python crashen zu lassen, was man natürlich mit einer Funktion hinbringt. Sondern es geht darum, vieviel Module man nachladen kann, ohne dass Python crasht. Und wenn es statt einer Zeile 3000 wären, dann würde Python nach 200 bis 300 maligem Laden crashen.

Und ich verstehe jetzt wirklich nicht, warum du so darauf versessen bist, dass ich den del nicht mache, damit dann Python crasht.
Den Beweis kann ich natürlich auch erbringen mit einem Modul crash.py:

Code: Alles auswählen

counter = 0
while True:


	a = "function"+str(counter)+": This isn't much, normally it should be a GUI"

	b = """def function"""+str(counter)+"""():
	print("""+'"'+a+'"'+""")
function"""+str(counter)+"""()
"""

	eval(compile(b,'<string>', 'exec'))
	
	counter += 1
Und einem Modul notcrash.py:

Code: Alles auswählen

counter = 0
while True:


	a = "function"+str(counter)+": This isn't much, normally it should be a GUI"

	b = """def function"""+str(counter)+"""():
	print("""+'"'+a+'"'+""")
function"""+str(counter)+"""()
del function"""+str(counter)+"""
"""

	eval(compile(b,'<string>', 'exec'))
	
	counter += 1
Hier ist dann noch das del eingefügt, sodass es nicht crasht
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Aber in deinem GUi Editor willst du doch nicht mit eval arbeiten, oder?

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
BlackJack

@Alfons Mittelmeyer: Wie viele Module kann man denn nun laden? Also welche die realen Bedingungen entsprechen. Und welche Anwendung hat dann so viele Module? Was immer Du da auch probiert hast und nicht zeigst, hat nichts mit realen Programmen zu tun, und zeigt damit auch kein reales Problem das Du mit ``del`` lösen kannst. Zumal Du dann noch zeigen müsstest *das* Dein ``del`` das dann gezeigte Problem auch löst und das Programm nicht alleine deswegen crasht weil so viele Module geladen wurden. Die Module bleiben als Objekte im Speicher ja auch erhalten wenn Du mit ``del`` den Funktionsnamen aus dem Namensraum löschst. Der Name selbst wird nicht gelöscht, und ob der Code der Funktion *tatsächlich* dadurch gelöscht wird, hast Du auch noch nicht gezeigt. Es bleibt also dabei das Du keinerlei Beweis für Deine Behauptung erbracht hast, und nur weiter dampfplauderst.
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

jens hat geschrieben:Aber in deinem GUi Editor willst du doch nicht mit eval arbeiten, oder?
Das will ich nicht so direkt. Das Problem wäre allerdings das Nachladen von Modulen. Mit import geht es nur einmal. Aber das Problem hat nichts mit Übergabe von Parametern zu tun und wäre später an anderer Stelle zu besprechen.
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

BlackJack hat geschrieben:@Alfons Mittelmeyer: Wie viele Module kann man denn nun laden? Also welche die realen Bedingungen entsprechen. Und welche Anwendung hat dann so viele Module? Was immer Du da auch probiert hast und nicht zeigst, hat nichts mit realen Programmen zu tun, und zeigt damit auch kein reales Problem das Du mit ``del`` lösen kannst. Zumal Du dann noch zeigen müsstest *das* Dein ``del`` das dann gezeigte Problem auch löst und das Programm nicht alleine deswegen crasht weil so viele Module geladen wurden. Die Module bleiben als Objekte im Speicher ja auch erhalten wenn Du mit ``del`` den Funktionsnamen aus dem Namensraum löschst. Der Name selbst wird nicht gelöscht, und ob der Code der Funktion *tatsächlich* dadurch gelöscht wird, hast Du auch noch nicht gezeigt. Es bleibt also dabei das Du keinerlei Beweis für Deine Behauptung erbracht hast, und nur weiter dampfplauderst.
Ich habe denn Beweis erbracht, dass Python crasht, wenn man die Funktionen nicht löscht. Und bei einem Webbrowser fragt man auch nicht, ob es reale Bedingungen sind, dass jemand mehr wie 50 Seiten aufruft und ob man deshalb die Seiten nicht aus dem Speicher wieder löschen muss. Und ob man del nicht benützen soll. Das ist alles Krampf. Ich lösche die Funktionen wieder und damit basta.

Und dass die Namen im Speicher bleiben ist auch Unsinn. Dann probiere doch mal:

Code: Alles auswählen

def function(): pass
print(function)
del function
print(function)
Ja Module, die man neben her braucht, etwa Klassen, die bleiben um Speicher. Beim Webbrowser bleiben das Browserprogramm und plugins ja auch im Speicher. Aber die Widgets und die Rückruffunktionen bleiben nur solange im Speicher, bis man sie löscht. Und wenn man eine andere Anwendung nachlädt, dann werden sie gelöscht. Da gibt es die Methode destroy in tkinter, von der Du eigentlich schon etwas gehört haben solltest.
lackschuh
User
Beiträge: 281
Registriert: Dienstag 8. Mai 2012, 13:40

@Alfons Mittelmeyer
nimm ein Memory Scanner bzw. ein Hex Editor und such danach. Du wirst sehen, dass alles noch im Speicher ist.
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

lackschuh hat geschrieben:@Alfons Mittelmeyer
nimm ein Memory Scanner bzw. ein Hex Editor und such danach. Du wirst sehen, dass alles noch im Speicher ist.
Wann dann die Müllentsorgung eingreift, kann egal sein. Und wie lange es man mit dem Hexeditor noch sehen kann, kann auch egal sein. Wichtig ist nur, dass man die Referenzen beseitigt. Das andere macht dann Python schon irgendwann. Das heißt dass Python den Speicher zum Überschreiben freigibt. Und irgendwann wird er dann überschrieben. Ob der Speicher zum Überschreiben freigegeben wurde, sieht man mit dem Hexeditor nur, wenn man die inneren Strukturen von Python und vom verwendeten C/C++ Compiler genau kennt. Aber man muss ja nicht alles genau kennen, um Python anzuwenden.
BlackJack

@Alfons Mittelmeyer: Du hast den Beweis erbracht das Python crasht, das war aber nicht die Frage, die Frage war nach realistischen Bedingungen. Bei einem Webbrowser würde mich natürlich stören wenn der nach 50 Webseiten abstürzt, aber es würde mich nicht im geringsten wundern wenn der nach mehr als 700.000 Webseiten in einem Programmlauf abstürzt. Ich wäre eher verwundert wenn der *das* wirklich schafft. Das wäre aber auch ein völlig unwichtiges da realitätsfernes Szenario. Zumal ich Dein Crashprogramm bei mir manuell abgebrochen habe als die 3 Millionen-Grenze überschritten war. Der Speicherverbrauch stieg zwar, aber so langsam das ich sehr wahrscheinlich bis 10 Millionen Funktionen hätte warten müssen. Was eine *extrem* unwahrscheinliche Anzahl an Funktionen für ein Programm wäre. Ausserdem sprachst Du ursprünglich mal von vielen Modulen die importiert werden und nicht von einem Modul in dem Unmengen an Funktionen erzeugt werden. Du kannst nicht dauernd das Ziel von Deinen Behauptungen ändern.

Namen bleiben im Speicher! Das Deine letzte Zeile den Namen in *dem Modul* nicht mehr erreicht, ändert nichts daran das der Speicher von einmal erzeugten Namen nicht wieder freigegeben wird. CPython macht das schlicht nicht, also wirklich *nie*. Falls Du da etwas anderes behaupten möchtest, zeig mir die Stelle im CPython-Quelltext wo das passiert. Das bedeutet das auch Dein `nocrash.py` deshalb *irgendwann* abstürzen wird. Entweder weil der Speicher voll ist, oder weil die maximale Anzahl von Elementen in der Datenstruktur (Hashtable) erreicht ist, in der die Namen für immer (also zur Laufzeit) gespeichert werden. In Deinem Beispiel *kann* der Name durch das ``del`` auch gar nicht freigegeben werden, denn auch wenn der Name/Wert-Verweis aus dem Modulnamensraum entfernt wurde, wird der Name in dem Code für das `print()` in der letzten Zeile natürlich noch gebraucht, denn dieser Code versucht den Wert zu dem Namen auszugeben, braucht folglich auch den Namen um nach dem Wert zu suchen — und dann als Namen im Modul nicht zu finden, aber zur Suche wird die Zeichenkette 'function' selbstverständlich noch benötigt.
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

GOTO:
jens hat geschrieben:z.Z. hängst du in der Premature optimization is the root of all evil Endlosschleife ;)

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

@BlackJack Sorry dass ich mir jetzt nicht manuell eine Million verschiedene Module geschrieben habe, sondern nur ein Modul, das die Funktionen dynamisch erzeugt. Und dass bei Dir auch noch bei 3 Millionen Aufrufen noch kein Crash kam, kann ich auch verstehen. Wahrscheinlich hat Dein Computer auch mehr als 1 GB Speicher. Und realistische Bedingungen sind nicht eine Funktion mit einer Programmzeile, sondern mit tausend und mehr Programmzeilen. Und bei 5000 Programmzeilen würde bei meinem Computer der Crash bei etwa 150 Aufrufen erfolgen, sofern es verschiedene Namen wären. Und ob die Namen im Speicher bleiben, kann man auch noch testen. Ich hatte nocrash.py schon bei etwa 1.300.000 Aufrufen abgebrochen. Ich kann ja noch mal einen Langzeittest starten.

Außerdem geht es auch nicht nur um die Namen, sondern auch um die Funktionen, die mit dem Namen verknüpft sind. Und da die Refernz nicht beseitigt wurde durch andere Verwendung des Namens oder dessen Löschung, bleiben die Funktionen im Speicher, da der Funktionsname auf die Funktion verweist. Und das Prinzip sollte sein, dass gelöscht wird. was nicht mehr benötigt wird. Das geschieht bei tkinter automatisch mit destroy. Bei der Funktion, welche die GUI erzeugte, geschieht das aber nicht. Und löschen kann man diese Funktion gleich nachdem sie ausgeführt wurde.
BlackJack

@Alfons Mittelmeyer: Wir drehen uns im Kreis. Natürlich kann man die eine Funktion welche GUI erstellt gleich nach dem ausführen versuchen zu löschen, das ist leider nur völlig irrelevant weil das nicht-löschen kein Problem ist, also muss da auch nichts gelöst werden. Das ist ganz einfach sinnfrei.

1000 und mehr Zeilen pro Funktion ist wieder so etwas vollkommen realitätsfernes. Solche Funktionen schreibt niemand der bei Verstand ist und wartbaren Code haben möchte. Und schon gar keine 150 solcher Funktionen mit 5000 Zeilen.

Das Prinzip sollte sein die automatische Speicherbereinigung ihre Arbeit erledigen zu lassen und keine Phantomprobleme zu lösen in dem man unsinnige ``del``\s im Programm verteilt. Du hast immer noch nicht gezeigt das hier ein *reales* Problem überhaupt *existiert*. Der Gegenbeweis sind alle Programme die diesen Unsinn nicht enthalten und trotzdem problemlos funktionieren. Also *alle* Programme. Ausser Deine.
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

@BlackJack Es geht nicht lediglich um eine Funktion mit 1000 Zeilen sondern auch um deren Unterfunktionen, denn wenn die Hauptfunktion nicht gelöscht wird, bleiben auch die Unterfunktionen im Speicher.

Habe den Crashtest nochmals laufen lassen und da die Ausgabe nur mehr nach tausend Funktionen gemacht, weil ich dachte, dass die Ausgabe stark bremst. Aber besonders viel schneller war es dann auch nicht.

Bei crash.py: Probleme ab 600.000 klitzekleine Fnktionen. Starke Beeinflussung des Gesamtsystems. Konnte die Maus kaum mehr bewegen. Kill nach 698.000 Funktionen. nocrash.py hatte ich am nächsten morgen nach über 85 Millionen Aufrufen abgebrochen.

Ob die Namen im Speicher bleiben weiß ich nicht. Jedenfalls ist es völlig unrealistisch, dass jemand täglich mehr als 85 Millionen Funktionsnamen benützt und Crash gab es da auch keinen. Nur wenn man Anwendungen mit verschiedenen Namen reinlädt und dort dann die Referenzen nicht beseitigt, dann müllen die Anwendungen immer mehr den Speicher zu. Und wenn man selber schon Anwendungen wie Word oder Grafikprogramme laufen hat, die selber Speicher brauchen, kann es schon bei huntertmaligem Laden größerer Anwendungen von ein paar tausend Zeilen Programmcode kritisch werden. Es ist unsinnig die Funktionen, welche die GUI aufbauen, also das, was zwischen tk() und mainloop() steht, bzw. ohne tk() und mainloop() beim Nachladen, im Speicher zu belassen und den Speicher immer mehr vollmüllen zu lassen.

Die Regel heißt, dass man dynamisch belegten Speicher, wenn man ihn nicht mehr braucht, auch wieder freigibt und nicht mehr und mehr zumüllt. Normalerweise sollte man spätestens nach Ende einer Anwendung den Speicher auch wieder freigeben. Also wenn es der Code für den Aufbau eines Frameinhaltes war, dann bei destroy des Frames oder dessen Inhaltes. Da aber der Code, der den GUI Aufbau macht, nur einmal benötigt wird, kann man ihn gleich nach Ausführung beseitigen. Also wenn man verschiedene Programmme unter Python laufen lässt und ohne Python zu beenden, die Programme dynamisch nachlädt, dann muß man selber den Speicher spätestend bei Beendigung dieser dynamisch nachgeladenen Anwendungen wieder freigeben. Aber die GUI Aufbau Funktionen kann man schon gleich nach Ausführung beseitigen.
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Alfons Mittelmeyer hat geschrieben:Bei crash.py: Probleme ab 600.000 klitzekleine Fnktionen. Starke Beeinflussung des Gesamtsystems. Konnte die Maus kaum mehr bewegen. Kill nach 698.000 Funktionen. nocrash.py hatte ich am nächsten morgen nach über 85 Millionen Aufrufen abgebrochen.
Huiii... Schon nach 600.000 geht es los? Das wird aber knapp werden, beim Projekt. Ich mache öfters GUIs mit mehr als über 2.000.000 Elemente... :K
jens hat geschrieben:GOTO:
jens hat geschrieben:z.Z. hängst du in der Premature optimization is the root of all evil Endlosschleife ;)

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

@Alfons Mittelmeyer: hier noch ein schöner Beitrag was Deine Probleme noch vergrößern könnte. Python ist einfach nicht dafür gemacht, unendlich viele Module zu laden. Ich würde vorschlagen, wenn Du bei halbunendlich vielen Modulen angekommen bist, können wir gemeinsam eine Lösung suchen, bis dahin solltest Du Dich wie jeder andere Python-Benutzer nicht explizit um Speicherverwaltung kümmern, das macht Python für Dich sehr gut.
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

@jens Mach Dich nur lustig. Die 600.000 bezogen sich auf ein Programm von der Größe 100 Byte. Es soll aber auch Programme mit 100 kByte geben. Vielleicht schon mal etwas von so großen Programmen gehört oder übersteigt das Dein Vorstellugsvermögen?
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Du merkst irgendwie nicht, das du in der Premature optimization is the root of all evil Endlosschleife bist, oder?!?

Wie oft willst du noch hören, das es realitätsfern ist?

Mach erstmal. Wenn du wirklich Speicherprobleme bekommst, kannst du drüber nachdenken...

Du denkt aber in einer Endlosschleife über fiktive Probleme nach...

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

Sirius3 hat geschrieben:@Alfons Mittelmeyer: hier noch ein schöner Beitrag was Deine Probleme noch vergrößern könnte. Python ist einfach nicht dafür gemacht, unendlich viele Module zu laden. Ich würde vorschlagen, wenn Du bei halbunendlich vielen Modulen angekommen bist, können wir gemeinsam eine Lösung suchen, bis dahin solltest Du Dich wie jeder andere Python-Benutzer nicht explizit um Speicherverwaltung kümmern, das macht Python für Dich sehr gut.
Es geht nicht um unendlich viele Module sondern um ein paar hundert. Und was dort geschieht ist im Prinzip nichts anderes wie viele Print Anweisungen auszugeben - nur dass es GUI Anweisungen sind, wie Button oder command=. Wenn man einfach eine Menge Printanweisungen macht, ist das kein Problem. Wenn man allerdings eine Menge Print Anweisungen in Funktionen packt, dann bleiben die Funktionen solange im Speicher, bis man sie löscht. Wenn man eine Menge Print Anweisungen in eine Funktion gepackt hat, und die aufgerufen hat, dann kann man sie auch wieder löschen.

Wenn Ihr nicht mit del einverstanden seid, bleib ich eben bei meinem Code und mach gar keine Funktion. Eine Lösung gäbe es auch, dass man dann zur Laufzeit nicht compiliert: man macht eine Liste aus lamda Anweisungen und macht sich dann auch noch eine GOTO Anweisung für bedingten und unbedingten Sprung und damit gehen sogar Schleifen.
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

jens hat geschrieben:Du denkt aber in einer Endlosschleife über fiktive Probleme nach...

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Gesperrt