5

アプリを作成するために wxPython で Python を使用しています。

これを達成するために私が考えている方法は最善ではないかもしれません - もしそうなら、私はリファクタリングを受け入れるので教えてください.

現在、1 つの GUI フォームがあります。メイン プログラムの開始点は、GUI フォームのインスタンスをインスタンス化し、次に wx.mainLoop() を実行します。これにより、アプリのメイン初期スレッドがアプリの存続期間中ブロックされます。

もちろん、UI でイベントが発生すると、UI スレッドがコードを実行することはわかっています。

今、別のスレッド、つまりワーカー スレッドがあります。このスレッドはアイドル状態である必要があり、UI スレッドで何かが発生したとき (ボタンがクリックされたときなど)、ワーカー スレッドがアイドル状態を停止して別のことを実行するようにします。たとえば、関数を実行します。

私は今これを想像することはできませんが、アプリがより複雑になるにつれて、実際に何かをしているときにワーカースレッドに通知する必要があることもわかりました.

このセットアップについて 2 つの質問があります。

  1. CPU 時間を使い果たすことなくワーカー スレッドをアイドル状態にするにはどうすればよいですか? のようなwhile True: passことをすると CPU 時間が消費while True: time.sleep(0.1)されますが、イベントへの即時の反応は許可されません。

  2. 何かを行うためにワーカー スレッドにシグナルを送る最良の方法は何ですか? UIスレッドに何かを実行させたくありません.UIスレッドによって、ワーカースレッドが何をしているのかを変更する必要があることを通知したいのです。理想的には、ワーカー スレッドが UI 自体にコールバックを登録する何らかの方法が必要です。これにより、ボタンがクリックされたとき、またはその他の UI イベントが発生したときに、ワーカー スレッドが動作を変更するように通知されます。

それで、これはこれを達成するための最良の方法ですか?そして、それを行うための最良の方法は何ですか?

ありがとう!

4

1 に答える 1

5

最初に: そもそもアイドル状態で待機するバックグラウンド スレッドが実際に必要ですか?

ほとんどのプラットフォームでは、新しいスレッドの開始は安価です。(超安価なWindows と Linux を除きます。) では、必要なときにいつでもスレッドを開始してみませんか? (スレッドのリストを保持するのは、単一のスレッドと同じくらい簡単ですよね?)

あるいは、単に を作成しThreadPoolExecutor、そこにジョブをサブミットするだけではなく、エグゼキュータがいつ、どのスレッドで実行されるかを心配できるようにします。「作業を待機する必要があるワーカー スレッド」ではなく、「メイン スレッドをブロックせずに実行する必要があるタスク」の観点から考えることができるときはいつでも、生活が楽になります。内部では、まだ 1 つまたは複数のワーカー スレッドがキューで待機している、または同等のものがありますが、その部分はすべて作成 (およびデバッグおよび最適化) されています。書く必要があるのは、通常の関数であるタスクだけです。

しかし、明示的なバックグラウンド スレッドを書きたい場合は、それを説明します。


CPU 時間を使い果たすことなくワーカー スレッドをアイドル状態にするにはどうすればよいですか? … ワーカー スレッドに何かを行うように通知する最良の方法は何ですか?

値の準備ができるまでスレッドをアイドル状態にする方法は、同期オブジェクトを待機することです。最新の OS では、同期オブジェクトを待機するということは、オブジェクトの準備が整うまで、オペレーティング システムが CPU 時間を提供しなくなることを意味します。*

モジュールのドキュメントで確認できるさまざまなオプションがありますがThreading、このようなほとんどの場合に使用する明白なオプションはCondition. ワーカー スレッドにシグナルを送る方法はnotifyCondition.

ただし、多くの場合、 aQueueははるかに単純です。を待機するには、そのメソッドを でQueue呼び出すだけです。別のスレッドにウェイクアップするように通知するには、. (カバーの下では、 aはorまたはその他のコレクション、 a 、および aをラップするため、値をチェックする、値が存在するまでブロックする、値を追加するなど、待機を処理する代わりに、やりたいことを伝えるだけです。コレクションのシグナリングと保護を行います。)getblock=TrueputQueueQueuelistdequeLockCondition

ワーカー スレッドから UI スレッドへ、およびその逆方向でシグナルを送信する方法については、スレッド化を使用して wxPython で UI 要素を制御する方法に関する回答を参照してください。


ワーカー スレッドが UI 自体にコールバックを登録する方法があれば、ボタンがクリックされるか、その他の UI イベントが発生したときに、ワーカー スレッドが動作を変更するように通知されます。

必要に応じて、このようにすることができます。self.queue.putor or anything をコールバックとして渡すだけdef callback(value): self.value = value; self.condition.notify()で、GUI スレッドは、コールバックが別のスレッドをトリガーしていることを知る必要さえありません。

実際、これは非常に優れた設計であり、後でコードをインラインとバックグラウンド スレッドの間で行ったり来たりしたり、バックグラウンド スレッドの代わりに子プロセスに移動したりすることにしたときに、非常に満足できるものです。


私は今これを想像することはできませんが、アプリがより複雑になるにつれて、実際に何かをしている間にワーカースレッドに通知する必要があることがわかりました.

しかし、忙しい場合はどうしたいですか?

「アイドル状態の場合は、目を覚ましてこのタスクを実行してください。それ以外の場合は、それを保持して、準備ができたらいつでも実行してください」と言いたいだけの場合、それはまさにQueue、またはExecutorが自動的に行うことです。

「暇なら起きて、それ以外なら気にしないで」と言いたいなら、ConditionorEventがそうします。

「アイドル状態の場合は、目を覚ましてこれを行います。それ以外の場合は、現在行っていることをキャンセルして、代わりにこれを行います」と言いたい場合、それはもう少し複雑です。バックグラウンド スレッドがビジー状態のときに "interrupt_me" 変数を定期的にチェックし (そしてそのLock周りに配置し)、そのフラグを設定して通知するCondition必要があります。アイドルとビジーのケースを単一のConditionorに変換しますEvent(アイドルの場合は無限を呼び出し、ビジーwait()の場合はクイックチェックを呼び出しwait(timeout=0)ます)。


* 場合によっては (Linuxfutexや Windows など)、CriticalSection実際には、CPU 時間を少しスピンオフすることがあります。これはたまたま適切な最適化であるためです。しかし要点は、使用する準備が整うまで、CPU 時間を要求していないということです。

于 2013-05-09T23:34:44.003 に答える