2010-12-05 6 views
0

Je me retrouve de plus en plus à SO récemment. Tout en essayant d'apprendre Python (en sautant à droite et en essayant de porter une application à partir de C#), j'ai découvert quelque chose dont je n'avais jamais entendu parler auparavant: Threading. Quand j'ai pensé que j'avais une compréhension basique, j'ai essayé de convertir la partie du programme qui zippe un répertoire plein de fichiers (et sous-répertoires). C'est ce que je suis venu avec à ce jour - avec l'aide de quelques sources que je vais énumérer à la fin:Filetage Python zipfile à utiliser avec barre de progression

from Queue import Queue 

import os 
import gtk 
import threading 
import time 
import zipfile 

debug = True 

class ProduceToQueue(threading.Thread): 
    def __init__(self, threadName, queue, window, maximum, zipobj, dirPath): 
     threading.Thread.__init__(self, name = threadName) 
     self.sharedObject = queue 
     self.maximum = maximum 
     self.zip = zipobj 
     self.dirPath = dirPath 
     self.window = window 

     global debug 

     if debug: 
      print self.getName(), "got all params." 

    def run(self): 
     if debug: 
      print "Beginning zip." 
     files = 0 
     parentDir, dirToZip = os.path.split(self.dirPath) 
     includeDirInZip = False 
     #Little nested function to prepare the proper archive path 
     def trimPath(path): 
      archivePath = path.replace(parentDir, "", 1) 
      if parentDir: 
       archivePath = archivePath.replace(os.path.sep, "", 1) 
      if not includeDirInZip: 
       archivePath = archivePath.replace(dirToZip + os.path.sep, "", 1) 
      return os.path.normcase(archivePath) 
     for (archiveDirPath, dirNames, fileNames) in os.walk(self.dirPath): 
      #if debug: 
       #print "Walking path..." 
      for fileName in fileNames: 
       time.sleep(0.001) 
       #if debug: 
        #print "After a small sleep, I'll start zipping." 
       filePath = os.path.join(archiveDirPath, fileName) 
       self.zip.write(filePath, trimPath(filePath)) 
       #if debug: 
        #print "File zipped - ", 
       files = files + 1 
       #if debug: 
        #print "I now have ", files, " files in the zip." 
       self.sharedObject.put(files) 
      #Make sure we get empty directories as well 
      if not fileNames and not dirNames: 
       zipInfo = zipfile.ZipInfo(trimPath(archiveDirPath) + "/") 
       #some web sites suggest doing 
       #zipInfo.external_attr = 16 
       #or 
       #zipInfo.external_attr = 48 
       #Here to allow for inserting an empty directory. Still TBD/TODO. 
       outFile.writestr(zipInfo, "") 

class ConsumeFromQueue(threading.Thread): 
    def __init__(self, threadName, queue, window, maximum): 
     threading.Thread.__init__(self, name = threadName) 
     self.sharedObject = queue 
     self.maximum = maximum 
     self.window = window 

     global debug 

     if debug: 
      print self.getName(), "got all params." 

    def run(self): 
     print "Beginning progress bar update." 
     for i in range(self.maximum): 
      time.sleep(0.001) 
      #if debug: 
       #print "After a small sleep, I'll get cracking on those numbers." 
      current = self.sharedObject.get() 
      fraction = current/float(self.maximum) 
      self.window.progress_bar.set_fraction(fraction) 
      #if debug: 
       #print "Progress bar updated." 

class MainWindow(gtk.Window): 
    def __init__(self): 
     super(MainWindow, self).__init__() 
     self.connect("destroy", gtk.main_quit) 
     vb = gtk.VBox() 
     self.add(vb) 
     self.progress_bar = gtk.ProgressBar() 
     vb.pack_start(self.progress_bar) 
     b = gtk.Button(stock=gtk.STOCK_OK) 
     vb.pack_start(b) 
     b.connect('clicked', self.on_button_clicked) 
     b2 = gtk.Button(stock=gtk.STOCK_CLOSE) 
     vb.pack_start(b2) 
     b2.connect('clicked', self.on_close_clicked) 
     self.show_all() 

     global debug 

    def on_button_clicked(self, button): 
     folder_to_zip = "/home/user/folder/with/lotsoffiles" 
     file_count = sum((len(f) + len(d) for _, d, f in os.walk(folder_to_zip))) 
     outFile = zipfile.ZipFile("/home/user/multithreadziptest.zip", "w", compression=zipfile.ZIP_DEFLATED) 

     queue = Queue() 

     producer = ProduceToQueue("Zipper", queue, self, file_count, outFile, folder_to_zip) 
     consumer = ConsumeFromQueue("ProgressBar", queue, self, file_count) 

     producer.start() 
     consumer.start() 

     producer.join() 
     consumer.join() 

     outFile.close() 

     if debug: 
      print "Done!" 

    def on_close_clicked(self, widget): 
     gtk.main_quit() 

w = MainWindow() 
gtk.main() 

problème est au bout d'environ 7000 fichiers les écluses du programme et je dois forcer le quitter . Je n'ai pas essayé avec moins de fichiers que ça, mais je pense que ça aurait probablement le même problème. En outre, la barre de progression ne se met pas à jour. Je sais que c'est désordonné (programmation style sage avec mixte underscored et CamelCase, et les erreurs noobish générales), mais je ne peux pas penser à aucune raison pour que cela ne fonctionne pas.

est ici où je suis le plus de ceci:

http://www.java2s.com/Code/Python/File/Multithreadingzipfile.htm http://www.java2s.com/Tutorial/Python/0340__Thread/Multiplethreadsproducingconsumingvalues.htm

Répondre

0

Je suppose que le file_count est faux et le consommateur attend toujours pour un autre objet à .get. Changer la ligne à current = self.sharedObject.get(timeout=5) et si c'est le cas, il devrait lancer une erreur à la fin.

En outre, oui, il existe de nombreux problèmes avec votre code - par exemple, lorsque vous utilisez GTK, vous ne voulez pas du tout vos propres threads. GTK possède sa propre bibliothèque de threads qui peut être utilisée en toute sécurité avec la boucle principale de GTK. Voir pages comme http://www.pardon-sleeuwaegen.be/antoon/python/page0.html ou google pour "gtk threading"

+0

'> par exemple lorsque vous utilisez GTK vous ne voulez pas du tout vos propres threads.' Qu'entendez-vous par là? Tous les autres tutoriels que j'ai vu sur le filetage avec GTK le font comme ça. – Micheal

+0

@Mike: Voir edit –

+0

Merci, je vais jeter un oeil et voir si je ne peux pas comprendre cette chose. – Micheal