Benutzerspeicher wächst

Fragen zu Tkinter.
Antworten
Benutzeravatar
Robin
User
Beiträge: 50
Registriert: Dienstag 26. Juni 2007, 10:47

Dienstag 18. November 2008, 16:37

Hallo Python-Forum,

habe mit folgendem Programm das Problem, dass der Benutzerspeicher ständig wächst, ca. 100k pro Minute, aber da das Programm Tag und Nacht laufen soll, ist es ein Problem. Wer kann helfen?

Code: Alles auswählen

import thread

def beenden():
      sys-.exit(-1)

def endlosschleife():
      .
      # Daten grafisch darstellen
      .

root=TK()
# Daten einlesen

thread.start_new_thread(endlosschleife,())

button=Buttom(root,text="Beenden",command=beenden)

root.mainloop()
BlackJack

Dienstag 18. November 2008, 17:11

Der Benutzerspeicher wächst!? Das wäre ja mal ein tolles Programm. Bei mir ist der immer gleich, eben was ich da an RAM in den Rechner gesteckt habe. ;-)

Aber ich glaub's auch aus einem anderen Grund nicht: Das Programm lässt sich nicht einmal kompilieren weil es syntaktisch nicht korrekt ist.

Wäre es das, würde einem ein `NameError` um die Ohren fliegen.

Dann darf man auf eine (Tk-)GUI nur aus dem Thread zugreifen, in dem auch die Tk-Hauptschleife läuft, sonst kann alles mögliche passieren.

Und das interessante in `endlosschleife()` unterschlägst Du. So kann man nur raten, dass Du wahrscheinlich in der Funktion endlos Objekte erzeugst.
lunar

Dienstag 18. November 2008, 17:14

Mit diesem Programm hast du mit Sicherheit gar keine Speicherprobleme, weil es nicht mal ein gültiges Programm ist. Und selbst wenn es das wäre, in 18 Zeilen unvollständigen Codes kann niemand ein Speicherleck finden.
Benutzeravatar
wuf
User
Beiträge: 1483
Registriert: Sonntag 8. Juni 2003, 09:50

Dienstag 18. November 2008, 17:24

Hallo Robin

Hier nur die startfähige Version (war nicht einfach):

Code: Alles auswählen

import Tkinter as tk
import thread
import sys

def beenden():
    sys.exit(-1)

def endlosschleife():
    # Daten grafisch darstellen
    print 'Hallo'
    pass

root=tk.Tk()
# Daten einlesen

thread.start_new_thread(endlosschleife,())

button=tk.Button(root,text="Beenden",command=beenden)
button.pack()

root.mainloop()
Gruss wuf
Take it easy Mates!
Benutzeravatar
wuf
User
Beiträge: 1483
Registriert: Sonntag 8. Juni 2003, 09:50

Dienstag 18. November 2008, 17:34

Hallo Robin

Hier eine start- und lauffähige Variante (ohne Modul 'thread'):

Code: Alles auswählen

import Tkinter as tk
#import thread
import sys

def beenden():
    sys.exit(-1)

def endlosschleife():
    # Daten grafisch darstellen (alle 100ms)
    print 'Hallo'
    root.after(100, endlosschleife)
    
root=tk.Tk()
# Daten einlesen

#thread.start_new_thread(endlosschleife,())

endlosschleife()
button=tk.Button(root,text="Beenden",command=beenden)
button.pack()

root.mainloop()
Gruss wuf :wink:
Take it easy Mates!
Benutzeravatar
wuf
User
Beiträge: 1483
Registriert: Sonntag 8. Juni 2003, 09:50

Dienstag 18. November 2008, 19:32

Hallo Robin

Hier ist noch etwas zum herumexperimentieren:

Code: Alles auswählen

import Tkinter as tk
import sys
from threading import Thread
from time import sleep
from random import randint

class Gui(object):

    IMAGE =\
    """
    R0lGODlhVABUAIQQAAAAACkTEzMYGEEeHkwjI1gpKWMuLnA0NHo5OYU+PpFE
    RJxISKdOTr1YWMhdXd9oaP//////////////////////////////////////
    /////////////////////////yH+FUNyZWF0ZWQgd2l0aCBUaGUgR0lNUAAh
    +QQBAAAQACwAAAAAVABUAAAF/iAkjmRpnmiqrmzrvnAsz3Rt33iu73zv/8Cg
    cEgsGo/IpHLJbDqf0Kh0Sq3mANisdsvlBqwiwIBALpvP6HLiK+2633CtE2Co
    E+oGAEFPBjwGD4EPdAGCgAMNiYoNA0NdJAAJkpMJenx7fwOaA4SGf4uKjSNe
    OJdkbGGUk5ZlfoCCnYGHoImiYWeoNXR4BrmRqpV7rX+Cg72eiLS2ELt4uTQA
    CNLSX1rAwZeuxbHEyaCcWMzT1KUM5uYBWJq/qqx9mZvcs8rmWefoN1gO+/sB
    AgAFCrCj5A7Tq0DyPinbB+Afv34AdGEqFmBPnYGrhL07aKyQLIXfEE4UFEDB
    Mhh0/vxQtJjnWkFtWDoio8VIpEqSDk6+SFnsQcVdGCW9/APgAANOxz56W/TK
    Us8AOaHlecoyaKVBwzgxYJRwaSibT//oAvDQQQAEQF1i3ZiJmMduNAcwdPgw
    gM4YAO4xSBcNrdpsxDy9nfetHha9z2YACMC4MbMsagFt3KTJ50xlm5g1ZnxX
    sYA+kCI/eNcz0GCQTCF93pPvjS2r2kaLoUz58rdRrmU0vMOrzmvRshPQCgxX
    2ahrkjqrgPMbWOw/wkERJ5w6TG68Ch4o2M7d5HHn02nXVhp3VPbSjHSf7769
    eTvipeNTD2U+fnrsgnq7Jwg/fs/5tYxiACWC3IfSeQ8k/qBde9+9x5F/xQBo
    IAAIKhiIgTtVGAiDqYD3IITkGReGhhcqlwKFglio3X6r9AdicbeNmGKBJqKA
    YiAqTgjci7ZVxwyJD2Dowo0J0tggfx+CKOFrQArZApE5vjaAhzxGiFotTM5Y
    onopJoBAAga8dpSDVfbISFRhDPhllFyi91oDY7aYJITUySWWjG7qhsVmfC0D
    AJxTCuWikiDZ6eeem6mjmAEINEJHoyb8GedzVc5jqAlnhSmOpotC+uhdkk5J
    KY+zXBopAppGw6lujDraqo2AjvriIaaemiqqNZ746qcnwumKeMDWVqutjuIq
    laev2vjnTWUis5yxquZq467Jup6QUrDYirdCtJtKay21kE4bLjMEHBATSYU4
    +eytq+IFrnK83vLoZggsEIC6KWRabLt4ZTYbvNVawug49d7rrQh2acJMZkX8
    O0q5WAxsb7oHg6GHub00Zq8D+IJho0Xj2Nuxx9ZCLDHFJO9Urk+NbZnykyv3
    xHHFJF/c08gvl2CzIDPnrPIBgfTs85BYHJCTwkM/mcc6/CY9rSh00Pxy1GlK
    nfJsYSDt9NZcd+3112CHLfbYZJdtdhQhAAA7
    """

    def __init__(self):
        self.window = tk.Tk()
        self.window.title('The Invaders')
        self.window.protocol("WM_DELETE_WINDOW", self.stop_it)
        self.window.configure(bg='steelblue')

        self.canvas = tk.Canvas(self.window, width=350, height=250, bg='black')
        self.canvas.pack(expand='yes')

        for image_obj in xrange(15):
            ImageObject(self, self.IMAGE)

        self.stop_button = tk.Button(self.window, fg='red', 
            font=('helvetica',12,'bold'), bd=1, highlightthickness=0,
            text='Please stop it !!!', command=self.stop_it)
        self.stop_button.pack(side='bottom', pady=4)

        self.window.mainloop()

    def stop_it(self):
        sys.exit(0)

class ImageObject(Thread):

    def __init__(self, gui, image):
        Thread.__init__(self)
        self.gui = gui
        self.plane = gui.canvas
        self.image = tk.PhotoImage(data=image)
        self.id = self.plane.create_image(100, 100, image=self.image)
        self.__restart()
        self.start()

    def __restart(self):
        self.plane.coords(self.id, randint(0,250), randint(30, 100))
        self.xpos = randint(-2, 2)
        self.ypos = randint(1, 3)

    def run(self):
        while 1:
            sleep(0.05)
            self.plane.move(self.id, self.xpos, self.ypos)
            if self.plane.coords(self.id)[1] > 150:
                self.__restart()

def main():
    gui = Gui()

if __name__ == "__main__":
    main()
Gruss wuf :lol:
Take it easy Mates!
yipyip
User
Beiträge: 418
Registriert: Samstag 12. Juli 2008, 01:18

Dienstag 18. November 2008, 22:58

Hallo wuf,
Du hast genau das passende Beispiel
für das Mysterium "Threads" gebracht.

Die entscheidenden Parameter sind
ja Anzahl der Image-Objekte und die
Zeit für sleep() in der run() Methode.

Erniedrigt man die Zeit für 'sleep()' und erhöht
die Anzahl der Objekte (also Threads)
so wird die Animation immer stockender
und es kann bis zum Einfrieren kommen.

Nehme ich extreme Werte
-- sleep(0.001), #Threads = 111 --
so erscheint zwar das Tk-Fenster, aber der Inhalt ist
der des Desktops dahinter.

Da ist wohl der GIL für verantwortlich?

:wink:
yipyip

P.S.
*Thumbs Up* für alle Deine Beispiele,
insbesondere für Deine faszinierende
Amateurfunk-Gui
Benutzeravatar
wuf
User
Beiträge: 1483
Registriert: Sonntag 8. Juni 2003, 09:50

Mittwoch 19. November 2008, 10:39

Hallo yipyip
yipyip hat geschrieben:Hallo wuf,
Nehme ich extreme Werte
-- sleep(0.001), #Threads = 111 --
so erscheint zwar das Tk-Fenster, aber der Inhalt ist
der des Desktops dahinter.
Ja damit kannst du dein Software-Prozessor einem 'Leistungs EKG-Test' aussetzen. :D
yipyip hat geschrieben: P.S.
*Thumbs Up* für alle Deine Beispiele,
insbesondere für Deine faszinierende
Amateurfunk-Gui
Danke für deine motivierenden Worte :wink:

@Robin

Hier eventuell eine Start-Variante für einen Thread-Test. Betreffs Memory-Verbrauch könnte vielleicht das Problem auch im grafischen Teil deines Programms liegen:

Code: Alles auswählen

import Tkinter as tk
import sys
from threading import Thread
from time import sleep

class Gui(object):

    def __init__(self):

        #~~ Erzeuge das Hauptfenster
        self.window = tk.Tk()
        self.window.title('Thread-Test')
        self.window.protocol("WM_DELETE_WINDOW", self.stop_it)
        self.window.configure(bg='steelblue')

        #~~ Erzeuge das Tread-Object
        self.my_thread_obj = TreadObject("Robin")

        #~~ Erzeuge die Stop Schaltflaeche
        self.stop_button = tk.Button(self.window, fg='red', 
            font=('helvetica',12,'bold'), bd=1, highlightthickness=0,
            text='Stop', command=self.stop_it)
        self.stop_button.pack(side='bottom', pady=4)

        self.window.mainloop()

    def stop_it(self):
        """Thread-Test beenden"""

        sys.exit(0)

class TreadObject(Thread):

    def __init__(self, name):
        """Konstruktor fuer ThreadObject"""

        self.name = name

        #~~ Initialisiere die geerbte Klasse Thread
        Thread.__init__(self)

        #~~ Starte die Endlosschleife ueber die Thread-Methode 'run'
        self.start()

    def run(self):
        """Endlosschleife"""

        while 1:
            sleep(0.1)
            print "Hallo %s" % self.name
            # Hier Daten grafisch darstellen 

def main():
    gui = Gui()

if __name__ == "__main__":
    main()
Gruss wuf :wink:
Take it easy Mates!
Benutzeravatar
Robin
User
Beiträge: 50
Registriert: Dienstag 26. Juni 2007, 10:47

Mittwoch 19. November 2008, 11:20

Hi WUF,
oh, ja, Du hast recht, der Fehler muss im grafischen Teil liegen.

Im Thread wandle ich dauernd aktuelle png-Datein einer
RoundRobinDatabase in GIF-Dateien um, damit ich sie
mit Hilfe von Photoimage über Labels in Tkinter darstellen kann.
Wenn ich diesen Bereich auskommentiere, bleibt der Speicher
stabil. Mache ich hier etwas falsch oder kann ich anderweitig
PNG-Bilder mit Tkinter darstellen?

Code: Alles auswählen

im = Image.open('/data/system/test.png')
name = '/data/system/test.gif'
im.save(name, "gif")
imb= PhotoImage(width=600, height=240,file=name)
lblb=Label(root,image=imb)
lblb.grid(row=0,column=0)
Gruß Robin
BlackJack

Mittwoch 19. November 2008, 11:43

Hör auf ständig neue `Label` zu erzeugen und ändere einfach bei *einem* Label die angezeigte Grafik, oder *zerstöre* die `Label`-Objekte auch explizit wieder.
Benutzeravatar
wuf
User
Beiträge: 1483
Registriert: Sonntag 8. Juni 2003, 09:50

Mittwoch 19. November 2008, 12:16

Hallo Robin

Du kannst .PNG's verwenden sofern du das Packet PIL (Photo-Image-Library) installiert hast.

Hier ein kleines Testprogramm:

Code: Alles auswählen

import Tkinter as tk
import Image
import ImageTk


test_window = tk.Tk()

pil_icon = Image.open("my_image.png")

pil_icon_1 = pil_icon.rotate(45)
pil_icon_2 = pil_icon.resize((70,70))

tk_icon = ImageTk.PhotoImage(pil_icon)
tk_icon_1 = ImageTk.PhotoImage(pil_icon_1)
tk_icon_2 = ImageTk.PhotoImage(pil_icon_2)

button = tk.Button(test_window, image=tk_icon)
button.pack(side='left')

button = tk.Button(test_window, image=tk_icon_1)
button.pack(side='left')

button = tk.Button(test_window, image=tk_icon_2)
button.pack(side='left')

test_window.mainloop()
Es ist aber nicht möglich PNG's im BASE64-Format anzuzeigen!

Gruss wuf :wink:
Take it easy Mates!
Benutzeravatar
wuf
User
Beiträge: 1483
Registriert: Sonntag 8. Juni 2003, 09:50

Mittwoch 19. November 2008, 12:33

Hallo Robin

Hier in etwa was 'BlackJack' gemeint hat:

Code: Alles auswählen

import Tkinter as tk
import sys
from threading import Thread
from time import sleep

class Gui(object):

    def __init__(self):

        #~~ Erzeuge das Hauptfenster
        self.window = tk.Tk()
        self.window.title('Thread-Test')
        self.window.protocol("WM_DELETE_WINDOW", self.stop_it)
        self.window.configure(bg='steelblue')

        #~~ Erzeuge das Tread-Object
        self.my_thread_obj = TreadObject(self.window, "Robin")

        #~~ Erzeuge die Stop Schaltflaeche
        self.stop_button = tk.Button(self.window, fg='red', 
            font=('helvetica',12,'normal'), bd=1, highlightthickness=0,
            text='Stop', command=self.stop_it)
        self.stop_button.pack(pady=4)

        self.window.mainloop()

    def stop_it(self):
        """Thread-Test beenden"""

        sys.exit(0)

class TreadObject(Thread):

    def __init__(self, parent, name):
        """Konstruktor fuer ThreadObject"""

        self.parent = parent
        self.name = name

        #~~ Initialisiere die geerbte Klasse Thread
        Thread.__init__(self)

        #~~ Erzeugt das Label-Objekt
        self.my_label = tk.Label(self.parent)
        self.my_label.pack()

        #~~ Starte die Endlosschleife ueber die Thread-Methode 'run'
        self.start()

    def run(self):
        """Endlosschleife"""

        while 1:
            sleep(0.1)
            print "Hallo %s" % self.name
#            my_image =  tk.PhotoImage(width=600, height=240,file='help.gif') #'my_image.gif')
            my_image =  tk.PhotoImage(file='my_image.gif')
            self.my_label.configure(image=my_image)

def main():
    gui = Gui()

if __name__ == "__main__":
    main()
Du musst nur noch das passende 'my_image.gif' zur Verfügung stellen.

Gruss wuf :wink:
Take it easy Mates!
Benutzeravatar
Robin
User
Beiträge: 50
Registriert: Dienstag 26. Juni 2007, 10:47

Mittwoch 19. November 2008, 13:39

Hi WUF und BlackJack,
ganz herzlichen Dank für Eure wertvollen Beiträge, ich denke sie sollten genügen,
damit ich ein funktionsfähiges Programm erzeugen kann. Zuerst probiere ich aus,
die Labels nicht immer wieder neu zu erzeugen. Wenn das nicht geht, nehme ich WUFs
letzten Sourcecode. Der sieht ja richtig gut aus!
Danke nochmals!
Robin
Antworten