2010-12-05 26 views
0

我發現自己越來越多地來到了最近。在嘗試學習Python時(通過直接跳入並嘗試從C#中移植應用程序),我遇到了以前從未聽說過的東西:線程。當我認爲我有一個基本的理解,我試圖轉換程序的一部分,該部分拉鍊目錄充滿文件(和子目錄)。這是我想出了迄今爲止 - 從幾個來源與幫忙,我會在最後列出:Python zipfile線程與進度條一起使用

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

問題與此是後約7000文件的程序鎖起來,我必須強制退出它。我還沒有嘗試過比這更少的文件,但我認爲它可能會有同樣的問題。此外,進度欄不會更新。我知道這很混亂(編程風格明智,混合強調和CamelCase,以及一般noobish錯誤),但我想不出任何理由不工作。

這裏就是我得到這個最:

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

回答

0

我猜的file_count是錯誤的,消費者永遠等待另一個目的是.get。將該行更改爲current = self.sharedObject.get(timeout=5),如果是這種情況,則應在最後引發錯誤。

另外,是的,您的代碼有很多問題 - 例如,當您使用GTK時,您根本不需要自己的線程。

GTK擁有自己的線程庫,可以安全地使用gtks主循環。請參閱http://www.pardon-sleeuwaegen.be/antoon/python/page0.html或Google的「gtk線程」頁面

+0

`>例如,當您使用GTK時,您根本不需要自己的線程。' 這是什麼意思?我在GTK上看到的其他每個教程都是這樣的。 – Micheal 2010-12-06 04:18:57