2012-07-27 22 views
1

我在pygtk中编写了一个工具,它需要处理递归解析大型目录,并将结果匹配的文件添加到列表中。这个过程显然会导致用户界面挂起,所以我试图使用多处理库。多线程 - 设计或代码问题时出现酸洗错误?

一些更多的背景,然后再问我一些解决方案: - 该程序有两个主要的类,一个控制器类,完成所有密集的工作并对UI讲话,一个Model类,用于处理所有数据工具需求。

import sys 
import os 
import pygtk 
import fnmatch 
from multiprocessing import Pool 
pygtk.require("2.0") 

#try: 
from gi.repository import Gtk 
from gi.repository import GObject 
#except: 
# print("GTK Not Availible") 
# sys.exit(1) 


class Controller(object): 
    def __init__(self,builder,model): 
     self.builder=builder 
     self.model=model 
    def btn_pass_clicked(self, *args,**kwargs): 
     print "it's working!, its woooooorkkinnnnggg!" 
     spinnywheel= self.builder.get_object("activitySpinner") 
     spinnywheel.start() 
    def btn_fail_clicked(self, *args, **kwargs): 
     print "stopping spinnywheel!" 
     spinnywheel=self.builder.get_object("activitySpinner") 
     spinnywheel.stop() 
    def quit(self,*args,**kwargs): 
     print "iamquit" 
     Gtk.main_quit() 
    def file_menu_open(self,*args,**kwargs): 
     print "file->open" 
     self.builder.get_object("openDialogue").show() 
    def opendialogue_btnOpen_clicked(self,*args,**kwargs): 
     rootdir = os.path.expanduser(self.builder.get_object("openDialogue_entryBox").get_text()) 
     self.builder.get_object("openDialogue").hide() 
     self.builder.get_object("openDialogue_entryBox").set_text("") 
     if os.path.exists(rootdir): 
      self.builder.get_object("activitySpinner").start() 
      print "pooling workers and walking ",rootdir 
      p = Pool(None) 
      p.apply_async(self.walk_for_files,rootdir,None,self.finished_recurse) 
     else: 
      print "Path does not exist!" 


    def walk_for_files(self,rootdir): 
      for root,dirs,files in os.walk(rootdir): 
        for extension in ['c','cpp']: 
         for filename in fnmatch.filter(files,'*.'+extension): 
          self.model.add_single_file(os.path.join(root,filename)) 

    def finished_recurse(self,*args,**kargs): 
     print "workers finished parsing dirs!" 
     self.builder.get_object("activitySpinner").stop() 


class Model(object): 
    def __init__(self): 
     self.fileList=[] 

    def add_single_file(self,file): 
     self.fileList.append(file) 
     print "added ",file 




class Scrutiny(object): 
    def __init__(self): 
     builder = Gtk.Builder() 
     builder.add_from_file("scrutinydev.ui") 
     model_object=Model() 
     controller_object=Controller(builder,model_object) 
     builder.connect_signals(controller_object) 
     builder.get_object("windowMain").show() 
     builder.get_object("listView") 
     GObject.threads_init() 
     Gtk.main() 



if __name__ == "__main__": 
    scrutiny = Scrutiny() 

现在,继承人我的问题。

正如您所看到的,使用pool()生成的工作人员需要执行回调finish_recurse,以便在其他UI工作中停止GtkSpinner。

随着其当前状态的代码,我得到一个错误的酸洗,

PicklingError: Can't pickle <type 'instancemethod'>: attribute lookup __builtin__.instancemethod failed 

我明白,这是因为我无法序列化回调,并想为为了解决方法/修复建议实现我所需要的。

+0

看看http://www.frozentux.net/2010/05/python-multiprocessing/;会帮助你吗? – 2012-07-27 09:40:24

+0

问题是,一个方法不包含告诉你它定义了哪个类的信息,这使得它不可能被腌制。我认为这可能会在未来版本的python中被修复(请参见[PEP 3155](http://www.python.org/dev/peps/pep-3155/)和[PEP 3154](http:// www .python.org/dev/peps/pep-3154 /)),但现在,您可以将'finished_recurse'转换为模块级功能。 – James 2012-07-27 09:49:47

+0

谢谢,我会看看那个链接martijn,但同时@james,你能详细说明代码中可能的样子吗?我是所有OO术语的新手。阅读:“我如何声明模块级功能?” – tel0s 2012-07-27 09:55:55

回答

0

我不太了解GTK,但我认为你的问题更多的是酸洗而不是多处理。

pickle module的__getstate__和__setstate__方法允许您为任何对象自定义酸洗过程。

这里是一个展示它是如何工作的一个简单的例子:

from pickle import dumps, loads 


class NotPickable(object): 
    def __init__(self, x): 
     self.attr = x 

ffile = open('/tmp/filesarenotpickable', 'r+w')  
o = NotPickable(ffile) 
dumps(o) 
# => TypeError: can't pickle file objects 

class Pickable(NotPickable): 
    attr = open('/tmp/a_file_on_an_other_system', 'r+w') 

    def __getstate__(self): 
     return self.attr.read() 

    def __setstate__(self, state): 
     self.attr.write(state) 

o = Pickable(ffile)            
dumps(o) 
# OUT: 'ccopy_reg\n_reconstructor\np0\n(c__main__\nPickable\np1\nc__builtin__\nobject\np2\nNtp3\nRp4\n.'       

o2 = loads(dumps(o))           
o2.attr 
# OUT: <open file '/tmp/a_file_on_an_other_system', mode 'r+w' at 0x18ad4b0> 

当然,它仍然是开发商的责任,代表和正确还原物体的状态。

+0

什么是attr.tag? – martineau 2012-07-27 10:53:11

+0

attr.tag是保存'toto'字符串的属性。我已经使用了etree.Element,因为它是我认为的第一个不可取的类,但它并不重要。 – 2012-07-27 12:15:55

+0

注意:我编辑了我的答案,以简单的文件替换etree.Element。它应该不那么令人困惑,显然,仅使用标准库的示例更可取。 – 2012-07-27 12:36:09