2010-09-09 10 views
3

J'ai le code suivant pour extraire un fichier tar.gz tout en gardant un œil sur les progrès:Pourquoi la barre de progression tkinter ralentit-elle les choses?

from __future__ import division 
import tarfile 
import os 

theArchive = "/Users/Dennis/Instances/atlassian-jira-enterprise-4.1.2-standalone.tar.gz" 

a = tarfile.open(theArchive) 

tarsize = 0 

print "Computing total size" 
for tarinfo in a: 
    tarsize = tarsize + tarinfo.size 

realz = tarsize 
print "compressed size: " + str(a.fileobj.size) 
print "uncompressed size: " + str(tarsize) 

tarsize = 0 

for tarinfo in a: 
    print tarinfo.name, "is", tarinfo.size, "bytes in size and is", 
    if tarinfo.isreg(): 
     print "a regular file." 
    elif tarinfo.isdir(): 
     print "a directory." 
    else: 
     print "something else." 
    a.extract(tarinfo) 
    tarsize = tarsize + tarinfo.size 
    print str(tarsize) + "/" + str(realz) 
    outout = tarsize/realz 
    print "progress: " + str(outout) 

a.close() 

Ceci est assez rapide et un extrait tar.gz 100 Mo 10 s. Je voulais avoir cette visuellement, si bien que je l'ai changé ce pour inclure une barre de progression tkinter:

from __future__ import division 
import tarfile 
import os 
import Tkinter 

class Meter(Tkinter.Frame): 
    def __init__(self, master, width=300, height=20, bg='white', fillcolor='orchid1',\ 
       value=0.0, text=None, font=None, textcolor='black', *args, **kw): 
     Tkinter.Frame.__init__(self, master, bg=bg, width=width, height=height, *args, **kw) 
     self._value = value 

     self._canv = Tkinter.Canvas(self, bg=self['bg'], width=self['width'], height=self['height'],\ 
            highlightthickness=0, relief='flat', bd=0) 
     self._canv.pack(fill='both', expand=1) 
     self._rect = self._canv.create_rectangle(0, 0, 0, self._canv.winfo_reqheight(), fill=fillcolor,\ 
               width=0) 
     self._text = self._canv.create_text(self._canv.winfo_reqwidth()/2, self._canv.winfo_reqheight()/2,\ 
              text='', fill=textcolor) 
     if font: 
      self._canv.itemconfigure(self._text, font=font) 

     self.set(value, text) 
     self.bind('<Configure>', self._update_coords) 

    def _update_coords(self, event): 
     '''Updates the position of the text and rectangle inside the canvas when the size of 
     the widget gets changed.''' 
     # looks like we have to call update_idletasks() twice to make sure 
     # to get the results we expect 
     self._canv.update_idletasks() 
     self._canv.coords(self._text, self._canv.winfo_width()/2, self._canv.winfo_height()/2) 
     self._canv.coords(self._rect, 0, 0, self._canv.winfo_width()*self._value, self._canv.winfo_height()) 
     self._canv.update_idletasks() 

    def get(self): 
     return self._value, self._canv.itemcget(self._text, 'text') 

    def set(self, value=0.0, text=None): 
     #make the value failsafe: 
     if value < 0.0: 
      value = 0.0 
     elif value > 1.0: 
      value = 1.0 
     self._value = value 
     if text == None: 
      #if no text is specified use the default percentage string: 
      text = "Extraction: " + str(int(round(100 * value))) + ' %' 
     self._canv.coords(self._rect, 0, 0, self._canv.winfo_width()*value, self._canv.winfo_height()) 
     self._canv.itemconfigure(self._text, text=text) 
     self._canv.update_idletasks() 

##-------------demo code--------------------------------------------## 

def _goExtract(meter, value): 
    meter.set(value) 
    if value < 1.0: 
     value = value + 0.005 
     meter.after(50, lambda: _demo(meter, value)) 
    else: 
     meter.set(value, 'Demo successfully finished') 

if __name__ == '__main__': 
    root = Tkinter.Tk(className='meter demo') 
    m = Meter(root, relief='ridge', bd=3) 
    m.pack(fill='x') 
    m.set(0.0, 'Computing file size...') 
    m.after(1000) 

    theArchive = "/Users/Dennis/Instances/atlassian-jira-enterprise-4.1.2-standalone.tar.gz" 

    a = tarfile.open(theArchive) 

    tarsize = 0 

    for tarinfo in a: 
     tarsize = tarsize + tarinfo.size 

    realz = tarsize 
    print "real size: " + str(tarsize) 
    print "compressed size: " + str(a.fileobj.size) 

    m.set(0.0, 'Done computing!') 
    m.after(1000) 

    tarsize = 0 

    for tarinfo in a: 
     print tarinfo.name, "is", tarinfo.size, "bytes in size and is", 
     if tarinfo.isreg(): 
      print "a regular file." 
     elif tarinfo.isdir(): 
      print "a directory." 
     else: 
      print "something else." 
     a.extract(tarinfo) 
     tarsize = tarsize + tarinfo.size 
     print str(tarsize) + "/" + str(realz) 
     outout = tarsize/realz 
     m.set(outout) 
     print "progress: " + str(outout) 

    a.close() 

    m.set(1.0, 'Extraction complete!') 
    m.after(1000) 
    m.after(1000, lambda: _goExtract(m, 0.0)) 

Il fonctionne bien beau, mais le processus prend maintenant plus de 2 minutes. Pourquoi cela arrive-t-il et comment puis-je résoudre ce problème?

Merci!

Dennis

Répondre

5

Quelle est la taille des fichiers de votre archive? Vous mettez certainement à jour la barre de progression beaucoup plus que nécessaire - il est courant d'inclure une vérification dans votre fonction set() pour qu'elle revienne juste sans mise à jour si le changement de la dernière valeur est trop petit. Avec une toile 300px, il n'y a absolument aucun intérêt à mettre à jour pour un changement de moins de 0.3% et probablement pas beaucoup de mise à jour plus souvent que tous les 1%. Comme votre processus se termine généralement en 10 secondes, vous pouvez également introduire une vérification basée sur le temps, car même une mise à jour tous les 1% sera 10 fois par seconde, ce qui est plus que nécessaire. Il serait intéressant de voir combien de temps Tk prend pour dessiner la barre si vous la conduisez à partir d'une simple boucle for.

+0

Une boucle simple est également plus lente car elle répète tous les 0,1%. Avez-vous des suggestions sur la façon de mettre à jour la barre de progression moins régulièrement? Comme tous les 1 ou 2% par exemple? – FLX

+0

Salut Andrew, grattez ça, je l'ai maintenant entièrement fonctionné en arrondissant la valeur de progression et en mettant une clause if entre les itérations pour vérifier si la progression a augmenté. Maintenant, il ne fait qu'une mise à jour partout où la progression se poursuit avec .01 pour cent, c'est très rapide maintenant :) – FLX

+0

Je suis content que vous l'ayez fait fonctionner :). –