Speicherverwaltung bei Programmausführung

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.
Antworten
jake-the-snake

Hallo Leute

Ich habe mal eine etwas andere Frage zum technischen Ablauf, bzw. zur Speichernutzung.
Aus der Antwort erhoffe ich mir, ggf. an den richtigen "Stellschrauben" für die Speicherverwaltung drehen zu können.

Ich habe in einem Programm ein Textfeld. Das wird, ebenfalls vom Programm, mit einer "String-Kette" vom USB-Stick vollgeschrieben.
Es handelt sich hierbei um eine Zeichenfolge, deren Inhalt im Beispiel hier 145,2 kB umfasst.
Um es vorweg zu nehmen: Das Programm funktioniert. Alle Funktionen des Programms werden auch rapide genug umgesetzt. Mir ist nur aufgefallen, dass ein Scrollen in dem Textfeld mit dieser langen Zeichenkette nur sehr langsam möglich ist. Man sieht, das hierbei immer wieder unterbrochen wird und man dann kurz warten muss.

Und hier die Fragen:

Ist der Platz, den eine Variable bietet ausreichend?
Kann der Platz, den eine Variable nutzt, irgendwo in einer Datei oder im System zugewiesen (vergrößert) werden?
Ist das vielleicht gar kein "Variablen-Platzproblem", sondern eher ein tkinter-Problem?

Naja, wie man sieht, suche ich das Nadelöhr, dass die "Fenster-Scrollfunktion" so stark verlangsamt...

Wer hat eine Idee, an was das liegen könnte?
Der Rechner hier hat 4GiB RAM und einen TripleCore-Processor - Da dürften doch 145,2 kB kein Problem darstellen :K

Gruß jts
__deets__
User
Beiträge: 14494
Registriert: Mittwoch 14. Oktober 2015, 14:29

Das Problem ist wahlweise tkinter, oder deine Programmierung desselben. Speicher wird in Python nicht statisch alloziert - im allgemeinen. Wenn man das doch macht, dann ist man sich dessen bewusst. Stattdessen wachsen Datenstrukturen bis zu der Groesse, die sie brauchen.
jake-the-snake

Abend _deets_

Das heisst ich müsste:
  • * die in das Textfeld geschriebene Zeichenkette so auftrennen, dass sie nur die Fenstergrösse füllt, und mit z. B. Up/Down Bottons neu befüllen
  • * alternativ das Scrollen komplett sperren (da diesesTextfeld eher symbolischen Charakter hat)
Würde es auch etwas bringen, den langen Textstring mit Umbrüchen in Textfeldgrösse zu versehen?

Gruß jts
OldBoy
User
Beiträge: 41
Registriert: Samstag 12. Januar 2008, 20:39

Ich habe in einem tkinter-Programm "ScrolledText"-Felder, in denen ich problemlos 60MB-Dateien anzeigen und verzögerungslos
scrollen kann. Was machen das GUI-Programm und der Rechner denn noch so nebenher?

Gruss, Oldboy
__deets__
User
Beiträge: 14494
Registriert: Mittwoch 14. Oktober 2015, 14:29

Was genau da hilft weiss ich nicht. Weniger Text wahrscheinlich, Zeilenumbrueche eher weniger (layouten muss das Ding eh). Unter Umstaenden gibt es da noch andere Muster, da hilft googeln/stackoverflow, Doku lesen und experimentieren. Das muss ja zB auch nicht im Rahmen deines Projektes sein, sondern kann auch ein eigenstaendiges Test-Skript sein, das du mit schnell wachsenden Testdaten befuellst.
jake-the-snake

Ich muss nochmal stören...

Wie lautet denn nochmal der genaue Befehl für die Installation von ScrolledText?
Wenn ich (Ubuntu 16.04) das eingebe...

[codebox=bash file=Unbenannt.bsh]sudo apt-get install ScrolledText[/code]

erhalte ich...

Code: Alles auswählen

Paket ScrolledText kann nicht gefunden werden.
Ich will mal das Modul testen.

Gruß jts
__deets__
User
Beiträge: 14494
Registriert: Mittwoch 14. Oktober 2015, 14:29

Das ist kein Paket das du installierst. Das ist eine Klasse in tkinter die es schon gibt & die du verwenden musst.
jake-the-snake

Hallo

Gut, aber wenn ich die Klasse im Python-Programm anwende und starte erhalte ich...

Code: Alles auswählen

Traceback (most recent call last):
  File "./test-raspi.py", line 21, in <module>
    from ScrolledText import *
ImportError: No module named 'ScrolledText'
Also fehlt doch da was?

Gruss jts
OldBoy
User
Beiträge: 41
Registriert: Samstag 12. Januar 2008, 20:39

"ScrolledText" gehört zu tkinter, mit Ubuntu 16.04:

- für Python2
python-tk package installieren
from ScrolledText import ScroilledText

- für Python3
python3-tk package installieren
from tkinter.scrolledtext import ScrolledText
jake-the-snake

Hallo Leute

OK, das mit ScrolledText hat funktioniert. Aber auch am Scrollschieber kann ich nicht flüssig herunter ziehen.
Das Problem ist eher noch schlimmer - langsamer - geworden. Also Scrollbalken bringen kein Geschwindigkeitsvorteil.

Wenn OldBoy 60MB flüssig scrollen kann, frage ich mich, warum mein Programm bei 145kB so langsam ist.
Zu den Rechnerumständen: Es laufen keine anderen Programme oder Berechnungen. Der PC hat quasi Urlaub! :lol:

Kann denn irgendwo der Speicher für den Window-Manager aufdrehen?

Gruss jts
Sirius3
User
Beiträge: 17712
Registriert: Sonntag 21. Oktober 2012, 17:20

@jake-the-snake: das ist kein Speicherproblem! Wahrscheinlich ein Darstellungsproblem. Da Du Dich aber zierst, zu zeigen, was Du tatsächlich machst, kann man da nur spekulieren.
bb1898
User
Beiträge: 199
Registriert: Mittwoch 12. Juli 2006, 14:28

Ganz blöde Frage, nur zur Sicherheit: liest Du den Text vom Stick vollständig, bevor Du ihn anzeigst? Andernfalls müsste man vielleicht auch nach der Übertragung gucken, ob es da hängt.
jake-the-snake

Abend Leute

Der USB-Stick wird vollständig eingelesen und erst dann komplett in das Textfeld gepackt.
Tests mit dem Programm zeigen:

Ist wenig Text im Textfeld, klemmt das Programm nicht. Das kann man anhand der "hover"-Funktion sehen, wenn man mit der Maus über die Schaltflächen fährt.

Ist viel Text im Textfeld (egal ob herein kopiert oder von USB gelesen), dann hinken die Schaltflächen ("hover"-Funktion), bzw sind stark verzögert.

Das Verhalten liegt eindeutig an der Textmenge. Das OldBoy 60MB im Textfeld "umher schubsen" kann, liegt vielleicht daran, das er die einzelnen Daten in unterschiedliche Variablen aufgeteilt hat? Ich habe eine Variable, deren Inhalt aus einer "Line"-Text besteht. Vielleicht ist das das Problem. tkinter muss ja an jedem Fensterende umbrechen. Wenn man die "Pfeil-herunter-Taste" drückt, kann man ja beinahe in Zeitlupe sehen, wie die unterste Zeile nach oben gerückt wird...

-> Kann man eine Indizierung der Textfelder bewirken, dass der PC quasi die Daten im Fenster vor ab liest?

Grus jts
__deets__
User
Beiträge: 14494
Registriert: Mittwoch 14. Oktober 2015, 14:29

Deine Vorstellungen über Speicher und wie man an ihm dreht haben etwas von einer Dampfmaschine...

Statt hier rumzuspekulieren wäre es mal gut, deinen Code zu sehen. Unter Umständen machst du etwas ungeschickt bei der Art, wie du den Text anzeigst.
jake-the-snake

Servus

Also mal ein Teilausschnit:

Code: Alles auswählen

####################
# USB-Import-Block #
####################

    def write_loadfromusb(self):
        print ("Lese Daten von USB")        
        # Linke Schrift Status-Feld         
        threeLabel = Label(root, text="Status: Lese Daten von USB...", font=("TimesNewRoman", 10), width=36, anchor=("w"))
        threeLabel.place(x=75,y=402)
        try:  
            # Datei fuer Lesezugriff oeffnen
            usbfh = open(usbpath, "r")
        except IOError:
            print ("Fehler beim Lesen von USB")
            # Linke Schrift Status-Feld 
            threeLabel = Label(root, text="Status: Fehler beim Lesen ...", font=("TimesNewRoman", 10), width=36, anchor=("w"))
            threeLabel.place(x=75,y=402)
            usbid = -1
            # USB-Photo-Anzeige OFF
            photo = PhotoImage(file="xxxxxx.gif")
            label = Label(image=photo)
            label.image = photo
            label.place(x=380,y=322)
            return
        # USB-Photo-Anzeige ON
        photo = PhotoImage(file="xxxxxx.gif")
        label = Label(image=photo)
        label.image = photo
        label.place(x=380,y=322)
        # Datei einlesen, wenn keine Fehler aufgetreten sind
        cryptocode = open(usbpath).read()
        # Endleerzeichen entfernen
        cryptocode = cryptocode.rstrip()
        # Schliessen der Datei
        usbfh.close()
        # Codefeldtext loeschen und befuellen
        codetextfeld.configure(state="normal")
        codetextfeld.delete('1.0', END)
        codetextfeld.insert(END, cryptocode)
        codetextfeld.configure(state="disabled")
        # Variable Reset
        cryptocode =""
        clearcode =""
        singlechain =""
        singlesign =""
        signcounter =""
        allsign =""

    def write_poweroff(self):
        if messagebox.askyesno("System-Rückfrage", "xxxxxx herunterfahren?"):
            print ("Jetzt wird abgeschaltet!")
            # os.system("shutdown -P now")

# Fenster-Titel
root = Tk(className=" xxxxxx")
root.resizable(FALSE,FALSE)
root.attributes("-topmost", 1)
root.wm_attributes('-type', 'splash')

# Knoepfe-App-Ende
app = App(root)

def center_window(width=300, height=200):
    # get screen width and height
    screen_width = root.winfo_screenwidth()
    screen_height = root.winfo_screenheight()

    # calculate position x and y coordinates
    x = (screen_width/2) - (width/2)
    y = (screen_height/2) - (height/2)
    root.geometry('%dx%d+%d+%d' % (width, height, x, y))
    
center_window(800, 480)

# Titel Schrift ueber Programm-Fenster 
zeroLabel = Label(root, text=" xxxxxx", font=("TimesNewRoman", 10), bg=('#999999'))
zeroLabel.place(x=305,y=28)

# Linke Schrift ueber Klartext-Feld 
oneLabel = Label(root, text="Klartext-Feld", font=("TimesNewRoman", 18))
oneLabel.place(x=75,y=65)

# Rechte Schrift ueber Codetext-Feld
twoLabel = Label(root, text="Codetext-Feld", font=("TimesNewRoman", 18))
twoLabel.place(x=585,y=65)

# Linkes Klartextfeld 
klartextfeld = Text(root, height=20, width=35)
klartextfeld.place(x=75,y=110)
klartextfeld.insert(END, "")

# Rechtes Codetextfeld 
codetextfeld = Text(root, height=20, width=35, takefocus=0)
codetextfeld.place(x=475,y=110)
codetextfeld.insert(END, "")
codetextfeld.configure(state="disabled")

# Main-Logo
photo = PhotoImage(file=" xxxxxx.gif")
label = Label(image=photo)
label.image = photo
label.place(x=360,y=65)

# mothersystem 123
if usbid == 108:
    # USB-Photo-Anzeige ON
    photo = PhotoImage(file="xxxxxx.gif")
    label = Label(image=photo)
    label.image = photo
    label.place(x=380,y=322)
    # Linke Schrift Status-Feld 
    threeLabel = Label(root, text="Status: Betriebsbereit...", font=("TimesNewRoman", 10), width=36, anchor=("w"))
    threeLabel.place(x=75,y=402)

if usbid == -1:
    # USB-Photo-Anzeige OFF
    photo = PhotoImage(file="xxxxxx.gif")
    label = Label(image=photo)
    label.image = photo
    label.place(x=380,y=322)
    # Linke Schrift Status-Feld 
    threeLabel = Label(root, text="Status: USB-Stick nicht erkannt / Neustart !", font=("TimesNewRoman", 10), width=36, anchor=("w"))
    threeLabel.place(x=75,y=402)

    # Rechte Schrift Typ-Feld 
    threeLabel = Label(root, text="Typ: xxxxxx", font=("TimesNewRoman", 10), width=36, anchor=("w"))
    threeLabel.place(x=475,y=402)

root.mainloop()
Von Zeile 54 bis Schluss ist der tkinter-Teil, der für das Fenster verantwortlich ist. Oberhalb von Zeile 54 ist z.B. einer von mehreren Befehlen, die über ein Button angesteuert werden. Soweit ich den Programmablauf verstehe, springt aber diese oberer Teil nur an, wenn eine Aktion eintritt - wie zum Beispiel auf den Button "USB - Import" zu drücken, der dann diese Einlesung veranlasst. So war das von mir zumindest gedacht, als ich das geschrieben habe.

Die Frage ist, ob ein Bewegen des Textfeldinhaltes mittels Pfeil-Tasten oder Maus-Scrollrad eine "Aktion" darstellt, der das Programm veranlasst, aus der "mainloop" zu springen?
__deets__
User
Beiträge: 14494
Registriert: Mittwoch 14. Oktober 2015, 14:29

Hui. Da ist ja ne Menge Cargo-Cult-Programmierung dabei. Dieses “leeren” von Variablen zb ist so wirksam wie ein Globuli bei Vollmond.

Welches ist denn das problematische Textfeld? codetextfeld? Und wer ruft write_loadfromusb auf?
jake-the-snake

Hi
Dieses “leeren” von Variablen zb ist so wirksam wie ein Globuli bei Vollmond
:lol: :lol: :lol: :lol:

Hier nützt das wahrscheinlich wenig... Ich habe einfach unter jeden Programmblock diesen Resetklotz gesetzt, um sicher zu gehen, dass sich nicht doch noch irgendwo her Überraschungen auftun (Fehler bei Variable-Belegung)

Aufgerufen wird dies von diesem Block:

Code: Alles auswählen

# Einleitung der App-Knoepfe
class App:
  
    def __init__(self, master):
        frame = Frame(master)
        frame.place(width=120, height=320, x=340, y=170)
        
        # End-Button
        self.poweroff = Button(frame,
                         text="►   Beenden   ◄", fg="black", pady=5, padx=5,
                         command=self.write_poweroff)
        self.poweroff.pack()

        # Code-Button
        self.coding = Button(frame, 
                         text="Verschlüsseln ►", fg="red", pady=5, padx=5,
                         command=self.write_coding)
        self.coding.pack()

        # Decode-Button    
        self.decoding = Button(frame,
                         text="◄ Entschlüsseln", fg="green", pady=5, padx=5,
                         command=self.write_decoding)
        self.decoding.pack()

        # Export-Button
        self.savetousb = Button(frame,
                         text="USB  - Export ▼", fg="black", pady=5, padx=5,
                         command=self.write_savetousb)
        self.savetousb.pack()

        # Import-Button
        self.loadfromusb = Button(frame,
                         text="USB  - Import ▲", fg="black", pady=5, padx=5,
                         command=self.write_loadfromusb)
        self.loadfromusb.pack()
Sieht doch soweit i. O. aus... :wink:

Gruss jts

PS. Das Problem-Textfeld ist "codetextfeld" - da es an Überfettung leidet... :)
Sirius3
User
Beiträge: 17712
Registriert: Sonntag 21. Oktober 2012, 17:20

@jake-the-snake: Speicher wird automatisch freigegeben, wenn er nicht mehr gebraucht wird, z.B. weil die lokalen Variablen am Ende einer Funktion abgeräumt werden. `usbfh` wird nicht verwendet. Man sollte kein `place` benutzen. Das eigentliche Problem dürfte sein, dass Du ständig Label und Images übereinander malst. Das alles muß bei jeder Cursorbewegung alles neu gezeichnet werden.
OldBoy
User
Beiträge: 41
Registriert: Samstag 12. Januar 2008, 20:39

Dein Text besteht offensichtlich aus einer einzelnen langen Zeile. Mit einer einzelnen 64KB langen Zeile ist mein Programm auch langsam.
Mit einer normale Textdatei mit 60 MB (ca 650.000 Zeilen) geht das Scrollen flüssig.

Gruss, Oldboy
jake-the-snake

Abend zusammen

Ich wollte nur kurz Feedback geben:

Für Testzwecke habe ich mir den Fensterinhalt in vielen "Einzelzeilen" (\n) anzeigen lassen und nicht in einer einzigen "Zeile". Programmbedienung und Scrolling jetzt ohne Probleme oder sonstige Auffälligkeiten möglich. :D

Ich denke, dass bei einer langen Zeile, die der Windowmanager "tk" bei der Anzeige ja mehrfach am Textfeldende umbrechen muss, jede Menge zu tun hat. Wird dann so eine "Mammutzeile" auch noch gescrollt, kommt es wohl rechnerrisch an seine Grenzen.

OldBoy hat somit den Nagel auf den Kopf getroffen und erhält 100 Punkte :wink:

Sirius3 hat auch recht, aber die paar übereinander "gemalten" Bildchen fallen hier nicht so ins Gewicht. :wink:

Danke für Eure Aussagen, ohne die ich gar nicht auf die Idee gekommen wäre, das Problem bei den Zeilen zu suchen...

Gruss jts
Antworten