0

Roger Stuckey の wxPython Multiprocessing コードを読んで、自分で同様のプログラムを作成しようとしました。完全なコードはここにあります。

コードは変更なしで正常に実行されます。ただし、パラメーターself.updateが GUI クラスMyFrameと処理クラスTaskSErverMPの間で渡されていることがわかりました。コード スニペット全体を検索しましたが、コード内で何をしているのかわかりませんでした。初期化も使用もされていません。

クラス MyFrame で:

def OnStart(self, event):
   ...
   self.taskserver.processTasks(self.update)
   ...

def OnStop(self, event):
   ...
   self.taskserver.processStop(self.update)
   ...

def update(self, output):
    """
    Get and print the results from one completed task.
    """
    self.output_tc.AppendText('%s [%d] calculate(%d) = %.2f\n'...
    ...
    # Give the user an opportunity to interact
    wx.YieldIfNeeded()

クラス TaskServerMP では:

def run(self):
   ...
   self.processTasks(self.update)
   ...

def processTasks(self, resfunc=None):
   ...

def processStop(self, resfunc=None): 
   ...

def update(self, output):
    """
    Get and print the results from one completed task.
    """
    sys.stdout.write('%s [%d] calculate(%d) = %.2f' % ....

だから私はそれが依存性注入の実践だと思ったが、それ以上のものではない. その後、コードから削除したところ、最も奇妙なことが起こりました。プログラムが機能しなくなりました! GUIが表示され、処理を開始できました。ただし、GUI がハングしただけで、後で Windows がプログラムが応答していないと報告しました。Windowsタスクマネージャーから手動ですべてのpythonw.exeプロセスを強制終了しました。

次に、クラスTaskServerMPの関数processTasksおよびprocessStopの署名と関係があるかどうかを考え始めますしかし、パラメーターself.updateをオプションの引数resfuncに関連付ける方法が本当にわかりません。

ロジャーのコードには何も問題はないと思います。しかし、コードの理解度をテストするためにソースをひねることができないと気になります。

Windows 7 で Python 2.7 を使用しています。

4

1 に答える 1

2

MyFrame.update方法です。365 行目でその定義を確認できます。

バインドされたメソッドも同様です。つまりself.update、通常の関数であるかのように呼び出すことができます。

パラメータをprocessTasks取ることがわかります。resfunc次に、少なくとも 165 で、そのresfuncパラメーターとして関数またはメソッドを取得した場合は、それを呼び出します。

ここでの考え方はprocessTasks、各タスクの完了時に進行状況の更新をどのように出力するかを決定するのは呼び出し元に任せるというものです。1 つのクラスは、それらを stdout に書き込むことによってそれを行うことができます。代わりに、別のクラスが GUI プログレス バーを更新する場合があります。

これは、Python コードでコールバックを渡す典型的な方法です。


では、なぜ ? を取り出すとプログラムがハングするのself.updateですか? さて、37​​2行目で、その中にあるものを見てください:

    # Give the user an opportunity to interact
    wx.YieldIfNeeded()

wx では、ほとんどの GUI フレームワークと同様に、メイン スレッドが「イベント ループ」を実行しています。これは、各イベント (マウスの移動、キー押下など) が発生したときにそれを処理し、次のイベントを待機するものです。コードは一連のイベント ハンドラーとして記述します。誰かがこのボタンをクリックすると、その関数が実行されます。など。イベント ハンドラはすぐに返さなければなりません。そうしないと、イベント ループが次のイベントを取得してディスパッチできないため、GUI が応答しません。wx では、一連Yieldの関数が生活を楽にします。十分な頻度で降参する限り、すぐに戻る必要はありません。ただし、早期に戻るか、Yield するかのいずれかを行う必要があります。そうしないと、GUI がハングします。


バインドされたメソッドの使用方法を示す非常に簡単な例を次に示します。

class Foo(object):
    def __init__(self, name):
        self.name = name
    def print_name(self):
        print(self.name)
    def give_me_a_printer_function(self):
        return self.print_name

spam = Foo('Spam')
my_function1 = spam.print_name
my_function2 = spam.give_me_a_printer_function()
my_function1()
my_function2()

Spamこれは2回印刷されます。

関数とメソッドはPython のファースト クラスの値です。数値、文字列、リスト、およびクラス インスタンスを渡すことができるのと同じように、関数とメソッドを渡すことができます。それらを印刷することもできます (ただし、 のような醜いものが得られます<bound method Foo.print_name of <__main__.Foo object at 0x104629190>>)。

于 2013-03-16T06:59:17.277 に答える