1

大きなディレクトリを再帰的に解析し、結果として一致するファイルをリストに追加する必要があるpygtkでツールを作成しています。このプロセスでは明らかにユーザー インターフェイスがハングアップするため、マルチプロセッシング ライブラリを使用してみました。

いくつかの解決策を尋ねる前に、もう少し背景を説明します。 - プログラムには 2 つのメイン クラスがあります。1 つは集中的な作業をすべて実行し、UI に話しかけるコントローラー クラスで、もう 1 つはツールが必要とするすべてのデータを処理するためのモデル クラスです。

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() で生成されたワーカーは、他の UI 作業の中で GtkSpinner を停止できるように、コールバック finish_recurse を実行する必要があります。

コードを現在の状態にすると、酸洗エラーが発生します。

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

これは、コールバックをシリアル化できないためであることを理解しており、必要なものを達成するための回避策/修正の提案を希望しています。

4

1 に答える 1

0

GTK についてはよくわかりませんが、あなたの問題はマルチプロセッシングよりもピクルスに関するものだと思います。

pickle モジュールの __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>

もちろん、オブジェクトの状態を表現して適切に復元することは、開発者の責任です。

于 2012-07-27T10:05:23.913 に答える