IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Tkinter Python Discussion :

[Tkinter][Text] Problème mémoire avec grand texte [Python 2.X]


Sujet :

Tkinter Python

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre Expert
    Avatar de transgohan
    Homme Profil pro
    Développeur Temps réel Embarqué
    Inscrit en
    Janvier 2011
    Messages
    3 149
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Maine et Loire (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur Temps réel Embarqué

    Informations forums :
    Inscription : Janvier 2011
    Messages : 3 149
    Par défaut [Tkinter][Text] Problème mémoire avec grand texte
    Bonjour,

    je rencontre actuellement des problèmes de mémoire qui impactent très rapidement les performances d'affichage de mon application.
    Pour faire simple c'est un widget Text avec une scrollbar qui affiche le contenu d'un fichier pouvant dépasser les 10ko de texte.
    Ce texte est parsé pour affecter des tags de couleur à certains mots. Le texte est ajouté au widget ligne par ligne et non en une seule fois.

    Au bout d'un certain nombre de ligne l'ajout se fait de plus en plus lentement.
    J'ai comme l'impression qu'il tente de redessiner tout le contenu du widget à chaque insert...
    Auriez-vous une idée pour palier à cela ?

    Dans le pire des cas je pensais à n'afficher que quelques lignes et recoder une scrollbar qui irait lire et parser le texte qui suit à la demande mais c'est assez lourd niveau code...
    Donc s'il existe une solution native pour palier à mon problème je suis tout ouïe.

  2. #2
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 754
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 754
    Par défaut
    Salut,

    Citation Envoyé par transgohan Voir le message
    Donc s'il existe une solution native pour palier à mon problème je suis tout ouïe.
    Pour pallier... il faudrait un diagnostic et pour avoir un diagnostic, il faut pouvoir reproduire et pour cela fournir un peu de code qui le permette.

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  3. #3
    Membre Expert
    Avatar de transgohan
    Homme Profil pro
    Développeur Temps réel Embarqué
    Inscrit en
    Janvier 2011
    Messages
    3 149
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Maine et Loire (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur Temps réel Embarqué

    Informations forums :
    Inscription : Janvier 2011
    Messages : 3 149
    Par défaut
    Je travaille sur un réseau coupé d'internet et duquel je n'ai pas le droit de rapatrier du code, sinon j'aurai inclus de suite ce dit code.

    Je vais cependant travailler sur un poc similaire pour tenter de vous poster du code, mais je n'ai aucune possibilité d'avoir un environnement python sur cet ordinateur...
    Donc pas facile de vous poster un code qui serait représentatif de mon problème et sans erreurs de code...
    J'ai trouvé des sites permettant d'exécuter du code python en ligne mais bloqué par le firewall de l'entreprise.
    Il ne me reste plus qu'à tenter de reproduire ce bug chez moi...

    Je continue d'investiguer et je m'oriente plutôt vers un problème de thread que du widget en tant que tel au final...

    Est-il possible d'avoir des réentrances d'une callback appelée avec la méthode after sur l'objet Tk ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    def maj :
      # ...
      # traitement x
      # ...
      Mafenetre.after(1000,maj)
    J'ai dans cette callback une fifo que je dépile, j'observe qu'il dépile pendant un temps des centaines de message en même temps puis au bout d'un moment il les dépile un à un.
    Comme si le scheduler était à la traîne...

    Note : cette fifo est remplie dans un autre thread (qui n'a rien à voir avec TKinter, et que je nommerai ThreadData).
    Note2 : j'ai déjà pu rendre l'affichage plus véloce en enlevant du threadData des printf sur la console (dans le gros volume de données il y en a qui sont incorrectes et donc qui ne peuvent être parsées).

    Niveau architecture voici en gros ce que fait mon programme (mais j'admets que du code serait mieux ) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    ThreadInput :
       Tant qu'il reste des choses à lire Faire :
           data = Lecture source
           Empiler data => fifo_data
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    ThreadData :
       Toujours Faire :
            data <= Dépiler fifo_data
            retour = Traitement(data)
            Si retour = OK Faire :
                 Empiler data => fifo_ihm
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    ThreadIhm :
    fonction update
         nb = 0
        Tant que nb < 500 ET fifo_ihm n'est pas vide Faire :
            data <= Dépiler fifo_ihm
            tags = détecter_tags(data)
            insérer data à Text_Tkinter
            insérer tags à Text_Tkinter
            nb++
         IHM.after(100, update)

  4. #4
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 754
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 754
    Par défaut
    Salut,

    Vous faites comme vous pouvez mais si vous voulez de l'aide pas facile de comprendre ce qu'il se passe sans un minimum de code. Tout au plus on peut essayer de coder l'histoire que vous racontez:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    from tkinter import Button
    from tkinter.scrolledtext import ScrolledText
    text = ScrolledText()
    text.tag_config("odd", background="yellow", foreground="red")
    text.tag_config("even", foreground="blue")
    text.pack()
     
    def addlines():
        line = int(text.index('end-1c').split('.')[0])
        for x in range(1, 100000, 2):
            text.insert('end', str(line + x) + '***' + 'ab' * 20 + '\n', "odd")
            text.insert('end', str(line + x + 1) + '***' + 'cd' * 20 + '\n', "even")
     
    Button(text='more', command=addlines).pack()
    Button(text='go end', command=lambda: text.see('end')).pack()
     
    text.mainloop()
    Et effectivement, lorsque je dépasse 1 million de lignes çà commence à peiner un peu mais, si je ne me trompe pas, çà dépasse largement les 10 Ko mentionnés au départ.

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

  5. #5
    Membre Expert
    Avatar de transgohan
    Homme Profil pro
    Développeur Temps réel Embarqué
    Inscrit en
    Janvier 2011
    Messages
    3 149
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Maine et Loire (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur Temps réel Embarqué

    Informations forums :
    Inscription : Janvier 2011
    Messages : 3 149
    Par défaut
    Je viens de rentrer à la maison et j'ai un peu de temps donc je vais m'installer l'environnement et je vais tenter de reproduire le problème.

    10k de texte qui doivent être interprétés, cela se transforme facilement en 100k de texte en fait à la fin.
    Cependant j'ai un collègue qui avec le même logiciel et 130k en entrée n'avait pas de ralentissement (mais il avait un fichier d'entrée nécessitant peu de traitement, donc ça rejoint un peu l'idée que c'est peut être plus le traitement que le widget en lui même).

  6. #6
    Membre Expert
    Avatar de transgohan
    Homme Profil pro
    Développeur Temps réel Embarqué
    Inscrit en
    Janvier 2011
    Messages
    3 149
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Maine et Loire (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur Temps réel Embarqué

    Informations forums :
    Inscription : Janvier 2011
    Messages : 3 149
    Par défaut
    Je viens de reproduire le problème et effectivement je m'oriente vers un problème de thread plus que de widget.

    Voici le poc :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    from tkinter import *
    import threading
    import sys
    import time
    import queue
     
    fin_thread_data_G = False
     
    taille_data_G = 0
    taille_lu_G = 0
    trame_G = ""
    nb_trame_G = 0
    def Traitement(octet_P) :
    	global taille_data_G
    	global taille_lu_G
    	global fifo_ihm_G
    	global trame_G
    	global nb_trame_G
     
    	if taille_data_G == 0 :
    		taille_data_G = 44 # taille de la chaine
    		trame_G = ""
    	if taille_lu_G < taille_data_G :
    		taille_lu_G = taille_lu_G + 1
    		trame_G = trame_G + chr(octet_P)
     
    	if taille_data_G > 0 and taille_data_G == taille_lu_G :
    		trame_G = trame_G + " " + str(nb_trame_G) + "\n"
     
    		array_texte = []
    		temp = trame_G.split("[texte")
    		array_texte.append({"text":temp[0], "color":"grey"})
    		tmp = temp[1].split("[/texte]")
    		c = tmp[0].split("]")
    		array_texte.append({"text":c[1], "color": c[0][1:]})
    		array_texte.append({"text":tmp[1], "color":"grey"})
     
    		nb_trame_G = nb_trame_G + 1
    		taille_data_G = 0
    		taille_lu_G = 0
    		while fifo_ihm_G.full == True :
    			time.sleep(1)
    		fifo_ihm_G.put(array_texte)
     
     
    def Thread_Data() :
    	global fifo_data_G
    	global fin_thread_data_G
     
    	with open("data.txt", "rb") as file : # 98819 éléments
    		octets = file.read()
    		for octet in octets :
    			while fifo_data_G.full == True :
    				time.sleep(1)
    			fifo_data_G.put(octet)
    	file.close()
    	print("\tfin Thread_Data")
    	fin_thread_data_G = True
    	return 0
     
     
    tag = 0
    def update() :
    	global fifo_ihm_G
    	global text
    	global ihm
    	global tag
     
    	nb = 0
     
    	while nb < 500 and fifo_ihm_G.empty() == False :
    		try :
    			texte = fifo_ihm_G.get(True, 0.0005)
    			for t in texte :
    				text.insert("end", t["text"])
    				start = "end -%dc" % len(t["text"])
    				end = "end -1c"
    				text.tag_add(tag, start, end)
    				text.tag_config(tag, foreground=t["color"])
    				tag = tag + 1
    			nb = nb + 1
    		except queue.empty :
    			print("empty %d" % nb)
    	print("fifo:%d" % nb)
    	text.see("end")
     
    	ihm.after(100, update)
     
    def Thread_IHM() :
    	global text
    	global ihm
     
    	ihm = Tk()
    	ihm.grid()
     
    	text = Text(ihm);
    	text.grid(row=0, column=0, sticky="NSEW")
    	scrollbar = Scrollbar(ihm, command=text.yview)
    	scrollbar.grid(row=0, column=1, sticky="NS")
     
    	ihm.grid_rowconfigure(0, weight=1)
    	ihm.grid_columnconfigure(0, weight=1)
    	ihm.grid_columnconfigure(1, weight=1)
     
    	ihm.after(100, update)
     
    	ihm.mainloop()
     
    def Thread_Parse() :
    	while fin_thread_data_G == False or fifo_data_G.empty() == False :
    		while fifo_data_G.empty() == True :
    			time.sleep(1)
    		octet = fifo_data_G.get(True, 0.5)
    		Traitement(octet)
    	print("\tfin Thread_Parse")
    	return 0
     
    def Main() :
    	t_ihm = threading.Thread(target=Thread_IHM)
    	t_data = threading.Thread(target=Thread_Data)
    	t_parse = threading.Thread(target=Thread_Parse)
     
    	t_ihm.start()
    	t_data.start()
    	t_parse.start()
     
    	t_ihm.join()
    	t_data.join()
    	t_parse.join()
     
    fifo_data_G = queue.Queue()
    fifo_ihm_G = queue.Queue()
    Main()
    data.txt (98819 fois cette chaîne de caractères)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Ceci est un [texte=red]test[/texte] de texte
    Je suis allé à l'essentiel pour reproduire l'architecture de mon programme et reproduire les ralentissements.
    Avec l'ajout des print j'observe que le thread de l'ihm ne reprend correctement la main que lorsque les deux autres ont terminés leur travail.
    (d'ailleurs, qu'existe-t-il pour Python afin de debugguer efficacement du multithread ?)
    On peut donc en penser que fifo.put ne lance pas le scheduler...
    Je n'observe cependant pas de latence du scroll une fois que les données sont toutes affichées, mais je le fait tourner actuellement sur un bon PC alors qu'au boulot c'est une chaudière ce qui explique peut être l'écart.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. problème calendar avec nested:text
    Par osman.amine dans le forum Struts 1
    Réponses: 1
    Dernier message: 05/11/2007, 11h36
  2. Problème mémoire avec InternetOpenUrl
    Par laetus dans le forum C++Builder
    Réponses: 0
    Dernier message: 06/09/2007, 08h23
  3. [VC6]Problème mémoire avec BDE
    Par Vow dans le forum MFC
    Réponses: 5
    Dernier message: 07/10/2005, 11h44
  4. Problémes mémoire avec le bde sur des bases paradox
    Par Keke des Iles dans le forum Bases de données
    Réponses: 2
    Dernier message: 27/05/2004, 16h55
  5. Problème mémoire avec une dll par chargement dynamique
    Par widze19 dans le forum C++Builder
    Réponses: 6
    Dernier message: 15/12/2003, 13h20

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo