最初に: そもそもアイドル状態で待機するバックグラウンド スレッドが実際に必要ですか?
ほとんどのプラットフォームでは、新しいスレッドの開始は安価です。(超安価なWindows と Linux を除きます。) では、必要なときにいつでもスレッドを開始してみませんか? (スレッドのリストを保持するのは、単一のスレッドと同じくらい簡単ですよね?)
あるいは、単に を作成しThreadPoolExecutor
、そこにジョブをサブミットするだけではなく、エグゼキュータがいつ、どのスレッドで実行されるかを心配できるようにします。「作業を待機する必要があるワーカー スレッド」ではなく、「メイン スレッドをブロックせずに実行する必要があるタスク」の観点から考えることができるときはいつでも、生活が楽になります。内部では、まだ 1 つまたは複数のワーカー スレッドがキューで待機している、または同等のものがありますが、その部分はすべて作成 (およびデバッグおよび最適化) されています。書く必要があるのは、通常の関数であるタスクだけです。
しかし、明示的なバックグラウンド スレッドを書きたい場合は、それを説明します。
CPU 時間を使い果たすことなくワーカー スレッドをアイドル状態にするにはどうすればよいですか? … ワーカー スレッドに何かを行うように通知する最良の方法は何ですか?
値の準備ができるまでスレッドをアイドル状態にする方法は、同期オブジェクトを待機することです。最新の OS では、同期オブジェクトを待機するということは、オブジェクトの準備が整うまで、オペレーティング システムが CPU 時間を提供しなくなることを意味します。*
モジュールのドキュメントで確認できるさまざまなオプションがありますがThreading
、このようなほとんどの場合に使用する明白なオプションはCondition
. ワーカー スレッドにシグナルを送る方法はnotify
、Condition
.
ただし、多くの場合、 aQueue
ははるかに単純です。を待機するには、そのメソッドを でQueue
呼び出すだけです。別のスレッドにウェイクアップするように通知するには、. (カバーの下では、 aはorまたはその他のコレクション、 a 、および aをラップするため、値をチェックする、値が存在するまでブロックする、値を追加するなど、待機を処理する代わりに、やりたいことを伝えるだけです。コレクションのシグナリングと保護を行います。)get
block=True
put
Queue
Queue
list
deque
Lock
Condition
ワーカー スレッドから UI スレッドへ、およびその逆方向でシグナルを送信する方法については、スレッド化を使用して wxPython で UI 要素を制御する方法に関する回答を参照してください。
ワーカー スレッドが UI 自体にコールバックを登録する方法があれば、ボタンがクリックされるか、その他の UI イベントが発生したときに、ワーカー スレッドが動作を変更するように通知されます。
必要に応じて、このようにすることができます。self.queue.put
or or anything をコールバックとして渡すだけdef callback(value): self.value = value; self.condition.notify()
で、GUI スレッドは、コールバックが別のスレッドをトリガーしていることを知る必要さえありません。
実際、これは非常に優れた設計であり、後でコードをインラインとバックグラウンド スレッドの間で行ったり来たりしたり、バックグラウンド スレッドの代わりに子プロセスに移動したりすることにしたときに、非常に満足できるものです。
私は今これを想像することはできませんが、アプリがより複雑になるにつれて、実際に何かをしている間にワーカースレッドに通知する必要があることがわかりました.
しかし、忙しい場合はどうしたいですか?
「アイドル状態の場合は、目を覚ましてこのタスクを実行してください。それ以外の場合は、それを保持して、準備ができたらいつでも実行してください」と言いたいだけの場合、それはまさにQueue
、またはExecutor
が自動的に行うことです。
「暇なら起きて、それ以外なら気にしないで」と言いたいなら、Condition
orEvent
がそうします。
「アイドル状態の場合は、目を覚ましてこれを行います。それ以外の場合は、現在行っていることをキャンセルして、代わりにこれを行います」と言いたい場合、それはもう少し複雑です。バックグラウンド スレッドがビジー状態のときに "interrupt_me" 変数を定期的にチェックし (そしてそのLock
周りに配置し)、そのフラグを設定して通知するCondition
必要があります。アイドルとビジーのケースを単一のCondition
orに変換しますEvent
(アイドルの場合は無限を呼び出し、ビジーwait()
の場合はクイックチェックを呼び出しwait(timeout=0)
ます)。
* 場合によっては (Linuxfutex
や Windows など)、CriticalSection
実際には、CPU 時間を少しスピンオフすることがあります。これはたまたま適切な最適化であるためです。しかし要点は、使用する準備が整うまで、CPU 時間を要求していないということです。