ThreadPool でスレッド作成
以前 QThreadでマルチスレッドを使う(Signalの注意点) という記事で、 QThread を継承して Thread を使用するサンプルを紹介しましたが、
これとは別にもう1つ「QThreadPool」を使用してスレッドを作成する処理のやり方があるので
紹介します。
Thread とは¶
PySide で GUI を作るときに、重い処理(ファイルのコピー等)を実行すると
実行中は GUI が操作できなくなり、プログレスバーなども進行を正しく表示できないなどの
問題が発生します。
そういった場合は、GUI とは別に処理を Thread 化して GUI を止めないようにします。
そのようなコードを書くときには QThread を継承したクラスを用意して、その run に
スレッド化したい処理を書く...といった事が可能ですが、
もっと細かいタスクを、大量に実行したいような場合には、 ThreadPool というクラスを使用した
スレッドの書き方をするのが有効です。
サンプル¶
全コードは こちらから。
処理は非常にシンプルで、Start ボタンを押すと、ランダムな秒数だけプリント分を実行し
終わったら finish task とプリントするスレッドを10個追加し、
スレッドは最大5個同時に処理する...といったサンプルコードになります。
ThreadPool をつかった場合の特徴は、Thread を管理するための QThreadPool クラスと、
実際のプロセスを実装するための QRunnable クラスで構成されています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
|
QRunnable は、QThread と基本共通で、
run 関数をオーバーライドすることで、Thread 化する処理を実装します。
QRunnable は、QObject の子クラスではないため、Signal は使用できません。
ので、Thread 内で Signal を使うために Signal 用のクラスを作成していますが
それ以外は非常にシンプルな構成になっています。
1 2 3 4 5 6 7 8 9 10 |
|
この QRunnable を使用するには、QThreadPool を作成し、pool.start(worker) で
実行する Runnable オブジェクトを渡します。
こうすると、指定の上限(setMaxThreadCount)だけ、別スレッドで処理が実行されます。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
実行例。
終了時やコメントの Signal を Runnable 側に作成してあるので
このように Signal-Slot を接続し、スレッドから Signal を受け取れるようにします。
この辺りは普通の PySide と同じです。
Close 時の処理¶
これでも一応動くのですが、このままだとツールを終了したときに
Thread が残ってしまうので、終了時にはのこりの Thread を終了するようにしておきます。
1 2 3 4 5 |
|
ThreadPool の場合どうするのが良いか迷いましたが、
QRunnable に終了する関数を追加しておき、Pool で実行中のスレッドがすべて終了するのを
待つようにします。
こうすることで、CloseEvent 時に実行中の Thread も待機中の Thread も
すべて終了してからツールが閉じるようになります。
まとめ¶
1つのスレッドのみで裏で実行するとかであれば、QThread を継承するのでもよいですが
ファイルコピーだったりといった処理は
この ThreadPool を使用するほうが、綺麗に書けることがあります。
また、定期的に実行するようなものも、Thread で実行する内容が複雑ならば、
細かく QRunnable に分けて実装し、
QTimer と組み合わせて ThreadPool に Runnable な Worker を投げる等する
といった使い方も便利だと思います。