2010-09-09 1 views
3

У меня есть следующий код для извлечения файла tar.gz в то время как сохранение вкладок на прогресс:Почему индикатор хода tkinter делает вещи намного медленнее?

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() 

Это довольно быстрый и извлекает 100MB tar.gz в 10 секунд. Я хотел, чтобы это визуально, а поэтому я изменил это, чтобы включить индикатор 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)) 

Он работает все хорошо и денди, но этот процесс в настоящее время занимает более 2 минут. Почему это происходит и как я могу это исправить?

Спасибо!

Dennis

ответ

5

Размер файла в вашем архиве: Вы почти наверняка обновляете индикатор выполнения намного больше, чем вам нужно - обычно включается проверка вашей функции set(), чтобы она просто возвращалась без обновления, если изменение от последнего значения слишком мало. С холстом 300px нет определенности в обновлении для изменения менее 0,3% и, вероятно, не так много в обновлении чаще, чем каждые 1%.

Поскольку ваш процесс обычно заканчивается через 10 секунд, вы можете также ввести проверку по времени, так как даже обновление каждые 1% будет 10 раз в секунду, что больше, чем вам нужно. Было бы интересно посмотреть, сколько времени займет Tk, чтобы нарисовать панель, если вы прогоните ее из простого цикла for.

+0

Простой цикл также замедляется, так как он также выполняет итерацию каждые 0,1%. Есть ли у вас какие-либо предложения о том, как обновлять индикатор прогресса менее регулярно? Как каждый 1 или 2%, например? – FLX

+0

Привет, Андрей, поцарапайте это, я получил его сейчас, полностью работая, округляя значение прогресса и помещая предложение if между итерациями, чтобы проверить, увеличился ли прогресс. Теперь он обновляет только там, где прогресс идет с 0,01 процента, сейчас очень быстро :) – FLX

+0

Рад, что у вас это работает :). –