2016-09-22 25 views
3

私は、グラフィカルユーザインタフェースを考えずにアプリケーションを書く方が好きです。アプリケーションコードが正常に動作したら、その上にGUIレイヤーを貼り付けることができます.2つの間にきれいなインターフェースがあります。アプリケーションスレッドとQtスレッド(Python-PyQt)をきれいに分ける

まず、アプリケーションから別のプロセスでGUIを実行しようとしました。しかし、すぐにその実験を後悔しました。 2つのプロセス間の通信リンクを設定することは、それほど簡単ではありません。だから私は今のところ、複数のスレッドが良いと判断しました(ただし、Pythonグローバルインタープリタロックはそれらを単一のコアで実行します)。

MainThreadは、完全にQt GUIの手に入ります。どうやら、これは標準的な習慣です。だから、私たちはソフトウェアの全体的な構造は次のようになりますと仮定してみましょう(qtThreadにMainThread同義であることに注意してください):

enter image description here

私のアプリケーション・コードがappThreadで実行されている - きれいGUIから分離されています。しかし、ある時点で、相互作用がなければならない。

私はこれを整理する方法について多くの記事を読んでいますが、多くの情報源は互いに矛盾しています。公式のQtアプリケーションでさえ、多くの人が間違っています(公式ドキュメントはQThreadをサブクラス化することを奨励しています)。私は見つけることができる最も啓発記事が、これらは以下のとおりです。

http://ilearnstuff.blogspot.be/2012/08/when-qthread-isnt-thread.html http://ilearnstuff.blogspot.be/2012/09/qthread-best-practices-when-qthread.html

でも、すべてのことを考慮した後、私はまだいくつかのことについて疑問が残ります。


質問1. appThreadを開始するための最も適切な方法は何ですか?


appThreadを開始するための最も適切な方法は何ですか?

選択肢1:私は間違っているが、私は二つの選択肢があることを信じているなら、私を修正し

import threading 

if __name__ == '__main__': 
    # 1. Create the qt thread (is MainThread in fact) 
    qtApp = QApplication(sys.argv) 
    QApplication.setStyle(QStyleFactory.create('Fusion')) 

    # 2. Create the appThread 
    appThread = threading.Thread(name='appThread', target=appThreadFunc, args=(p1,p2,)) 
    appThread.start() 

    # 3. Start the qt event loop 
    qtApp.exec_() 
    print('Exiting program') 

Pythonは1は、新しいスレッドを生成するためにインポートすることができ threadingライブラリを提供し、標準のPythonのスレッドを開始

この選択は私には一番きれいです。 appThreadコードをGUIについて考えることなく真に書くことができます。結局のところ、標準のPython threadingライブラリを使用しています。そこにはQtのものはありません。
のアプリスレッドのメインスレッドの間の通信リンクの設定についての明確な文書は見つかりません。 2番目の質問でその問題についてもっと詳しく..

選択肢2:あなたは、あなたのアプリケーションのコードを書くためにQtのものを台無しに持っているので、この選択は、それほどきれいではないに見えるQThreadスレッド
を開始します。とにかく、両方のスレッド(appThreadMainThread)間の通信リンクがおそらくサポートされているため、実行可能なオプションのように見えます。
QThreadスレッドを開始する方法はたくさんあります。 Qtの公式文書では、QThreadをサブクラス化し、run()メソッドを再実装することを推奨しました。しかし、私はこの練習が実際には非常に悪いと読む。私の質問の冒頭に投稿した2つのリンクの詳細を参照してください。


質問2.両方のスレッド間で最良の通信リンクとは何ですか?


両方のスレッド間で最良の通信リンクとは何ですか?明らかにこの質問に対する答えは、質問1で行われた選択に大きく依存します。標準のPythonスレッドをGUIにリンクすることは、QThreadをリンクすることとは非常に異なっていると思います。
私は提案を作るためにあなたにそれを任せますが、私の心にポップアップし、いくつかのメカニズムは以下のとおりです。

  • キュー:Pythonの標準キューまたはQtのキューを使用していますか?
  • シグナル/スロットメカニズム:...
  • ソケット:動作するはずに、少し面倒になります
  • パイプ:...
  • 一時ファイル:面倒な


注:


回答がPython 2.xまたは3.xに該当するかどうかをご記入ください。また、スレッド、キューなどについて話すときに、混乱が迅速に発生する可能性があることにも注意してください。標準のPythonスレッド、QThread、標準のPythonキュー、またはQQueueを参照している場合は、言及してください...

+0

なぜフロントエンドとバックエンドに別々のスレッド/プロセスを使用する必要があると思いますか?バックエンドはGUIをブロックしていますか?そうでない場合、これはむしろ意味のない質問であるように見えます。しかし、たとえそれがブロックされても、あなたが質問を構成した方法は、多くの意見に基づく回答を招くようです。 SOは、ソフトウェア設計の一般的なアプローチではなく、特定のプログラミング上の問題*に関するものです。 – ekhumoro

答えて

1

私が示唆しているのは、ほとんどの人が行うことです。別のスレッドで実行する必要のあるコードがあるまで待ってから、だけをスレッドに挿入します。優れたコード分離を得るために、コードを別のスレッドに入れる必要はありません。私がそれをする方法は次のとおりです:

あなたのappThreadコード(GUIの知識がないコード)は、GUI以外のライブラリに関する知識しか持っていません。これにより、後でコードのコマンドラインバージョンを簡単にサポートすることができます。この基本クラスに対して、通常のPythonスレッド内で非同期で実行する必要があるコードを入れてください。非同期に実行するコードが、次のポイントを簡単にするための単なる関数呼び出しであることを確認してください。

次に、作成した基本クラスとQMainWindowクラスの両方から継承する子クラスを別のファイルに作成します。非同期に実行する必要のあるコードは、QThreadクラスを介して呼び出すことができます。上記のように、1つの関数呼び出しで非同期で実行したいコードを作成した場合は、QThreadの子クラスに対してこのステップを簡単に実行できます。

上記の理由は何ですか?

多くの場合、状態と通信の管理が容易です。競争条件やスレッド通信が必要ないときに、なぜあなた自身が狂ってしまうのですか?また、アプリケーションコードとGUIコードのGUIに別々のスレッドを持つパフォーマンス上の理由もありません。なぜなら、ほとんどの場合、ユーザーが実際にはCPUに関する限り多くの情報を入力していないからです。問題のないようにしてコード管理を容易にするために、遅いパーツだけをスレッドに入れるべきです。さらに、Pythonでは、GILのおかげで別のスレッドから何も得られません。

関連する問題