多くの場合、プログラムではマルチスレッドを使用する必要があります。 これらは複雑な相互作用を伴うモンスターのようなスレッドプールである場合もありますが、多くの場合、これは単純なコードであり、その主な要件はインターフェイスをフリーズしないことです。
PyQtには、高レベルのスレッドを操作するための2つの主要なツールがあります。PythonスレッドとQt QThreadです。 私にとっては、Qtのシグナルスロットメカニズムとの接続が良好であるため、QThreadの方が望ましいと判明しました。
そのため、ツールが選択され、すべてが正常に機能しますが、時間が経つにつれて、ストリームの処理を多少簡単で便利にしたいと思いました。 単純なケースでは、
自転車をフローのある仕事のモジュールにするアイデアがありました。
simple_thread
この
モジュールは 、QObjectから継承されたクラスのストリームで動作するように設計されています。 これを使用すると、任意のクラスメソッドを別のスレッドで強制的に実行できます。一方、メソッド内では、クラスの属性とメソッドに(限定的ではありますが)アクセスできます。
簡単な例を見てみましょう:
Fooクラスは
QLabelを継承して
おり 、インターフェイスをフリーズせずに0.5秒ごとにラベルテキストを変更します。
barメソッドはテキスト
出力を処理し
ます 。 このメソッドを別のスレッドで動作させるには、メソッドを宣言する前に
@SimpleThreadデコレーターを配置します。
メソッド内から、
digits属性(表示される単語のリスト)にアクセスする必要があります。 また、ラベルテキストを更新する必要があります。そのために、
setTextメソッドを呼び出します。
属性アクセス
最初の問題は、このスレッドだけでなく
数字も使用できることです。
simple_threadモジュールはこの問題を回避します。 属性を受け取ると、この属性へのリンクではなく、そのコピーが返されます。 同時に、すべてのアクションはメインスレッドのコンテキストで発生するため、複数のスレッドから同時に属性にアクセスすることを心配する必要はありません。
この方法で、リスト、辞書、およびすべての不変のクラス属性(文字列、タプルなど)にアクセスできます。
ここには1つのポイントがあります。動作が非常に遅いため、属性にアクセスして無理をしないでください。
メソッド呼び出し
問題2は
setTextメソッドを呼び出しています。 問題は最初の問題と似ています-メインスレッドからではなくグラフィッククラスメソッドにアクセスしようとすると、Qtは例外をスローします。 最初の場合と同様に、これはスレッドを中断し、メインスレッドからメソッドを呼び出すことで解決されます。
thr_method引数に応じて、メソッドを呼び出す3つの異なる方法があります。
- thr_method = 'b' :メソッドが呼び出されると、スレッドはメソッドが終了するまで一時停止します。 メソッドの実行はメインスレッドで行われます。 この場合のみ、メソッドの戻り値を内部で取得します。
- thr_method = 'q' :この場合、スレッドは停止しません。 メソッドはメインスレッドでも実行されます。
- thr_method = Noneまたはnot set :メソッドの実行はスレッドのコンテキストで発生します。 ここで注意する必要があります-マルチスレッドに関連するすべての制限が有効になります。特に、メソッドのクラス属性にアクセスできません。
thr_method引数は、呼び出されたメソッドに渡されません。
属性を設定する
別のスレッドから属性を設定することもできます。
self.newAttr = 'text'
属性はどのタイプでもかまいません。
他の場合と同様に、すべての作業はメインスレッドで実行され、問題は発生しません。属性を設定することで、既存の属性を消去できることを覚えておく必要があります。
ストリーム開始
コードを実行するには、スレッドがすぐに開始されるように
thr_start = True引数を指定して
barメソッドを実行するだけです。
別の方法があります。別のスレッドから呼び出されたシグナルまたはクラス
QThreadのシグナル(
started 、
finished 、
terminate )を処理する場合に便利です。
thread = foo.bar('From thread') thread.finished.connect(self.barFinished) thread.start()
ここでは、
終了したストリームの終了信号を
barFinishedメソッドに接続し、ストリームを開始しました。
フローストップ
何らかの理由で実行中のスレッドを停止する必要がある場合、
thr_stopメソッドを呼び出すことでこれを実行できます。
thread = foo.bar('From thread', thr_start = True) ... thread.thr_stop()
このメソッドはフラグ
thr_stopFlag = Trueを設定します。この状態はメソッドで監視する必要があり、trueの場合はメソッドを終了します。
thr_stopメソッド
はスレッドが停止するのを待たず、すぐに制御を返すことに注意して
ください 。 スレッドの動作が完了するのを待つ必要がある場合は、
thr_stopの後に
waitメソッドを呼び出す必要があります。
simple_threadモジュールには、すべてのアクティブなスレッドを停止するための2つの関数
-terminateThreadsと
closeThreadsがあります。 最初の関数は、すべてのスレッドの実行を著しく中断しますが、これは安全ではない場合があります。 2番目の関数は、スレッドごとに
thr_stopを呼び出したように機能し、
待機します。
すべてのコメント、提案などを歓迎します。 このようなものが既に誰かによって実装されている場合、私はリンクさせていただきます。