質問

ご質問:

  1. 何が最良の実践 身体の安全を確保するためのトレッドの 進捗なロックのGUI ない回答")?
  2. 一般に、何のためのベスト-プラクティス スレッドとしてこの制度の対象となるGUI 開発?

質問の背景

  • いPyQt GUIします。
  • での処理に使用のHTML を提出する。
  • なかでもどこでもか秒 時過程でのセット を提出する。
  • こういうことができるよう処理 複数のセットでも同時に行います。
  • 私たいと思っているGUIをロックになっています。
  • 私のスレッドモジュール この目標を達成する
  • 私は比較的新しいスレッド.
  • のGUIを持つ進捗バーがあります。
  • っていない場合については、表示の進歩 を選択します。
  • 結果の表示の選択 スレッドの場合は終了しました。
  • 私が使っているPython2.5.

自分の考: てのスレッドが発QtSignalが進捗状況の更新をトリガする一部の機能が更に進捗バーがあります。また信号合成処理結果を表示することができます。

#NOTE: this is example code for my idea, you do not have
#      to read this to answer the question(s).

import threading
from PyQt4 import QtCore, QtGui
import re
import copy

class ProcessingThread(threading.Thread, QtCore.QObject):

    __pyqtSignals__ = ( "progressUpdated(str)",
                        "resultsReady(str)")

    def __init__(self, docs):
        self.docs = docs
        self.progress = 0   #int between 0 and 100
        self.results = []
        threading.Thread.__init__(self)

    def getResults(self):
        return copy.deepcopy(self.results)

    def run(self):
        num_docs = len(self.docs) - 1
        for i, doc in enumerate(self.docs):
            processed_doc = self.processDoc(doc)
            self.results.append(processed_doc)
            new_progress = int((float(i)/num_docs)*100)

            #emit signal only if progress has changed
            if self.progress != new_progress:
                self.emit(QtCore.SIGNAL("progressUpdated(str)"), self.getName())
            self.progress = new_progress
            if self.progress == 100:
                self.emit(QtCore.SIGNAL("resultsReady(str)"), self.getName())

    def processDoc(self, doc):
        ''' this is tivial for shortness sake '''
        return re.findall('<a [^>]*>.*?</a>', doc)


class GuiApp(QtGui.QMainWindow):

    def __init__(self):
        self.processing_threads = {}  #{'thread_name': Thread(processing_thread)}
        self.progress_object = {}     #{'thread_name': int(thread_progress)}
        self.results_object = {}      #{'thread_name': []}
        self.selected_thread = ''     #'thread_name'

    def processDocs(self, docs):
        #create new thread
        p_thread = ProcessingThread(docs)
        thread_name = "example_thread_name"
        p_thread.setName(thread_name)
        p_thread.start()

        #add thread to dict of threads
        self.processing_threads[thread_name] = p_thread

        #init progress_object for this thread
        self.progress_object[thread_name] = p_thread.progress  

        #connect thread signals to GuiApp functions
        QtCore.QObject.connect(p_thread, QtCore.SIGNAL('progressUpdated(str)'), self.updateProgressObject(thread_name))
        QtCore.QObject.connect(p_thread, QtCore.SIGNAL('resultsReady(str)'), self.updateResultsObject(thread_name))

    def updateProgressObject(self, thread_name):
        #update progress_object for all threads
        self.progress_object[thread_name] = self.processing_threads[thread_name].progress

        #update progress bar for selected thread
        if self.selected_thread == thread_name:
            self.setProgressBar(self.progress_object[self.selected_thread])

    def updateResultsObject(self, thread_name):
        #update results_object for thread with results
        self.results_object[thread_name] = self.processing_threads[thread_name].getResults()

        #update results widget for selected thread
        try:
            self.setResultsWidget(self.results_object[thread_name])
        except KeyError:
            self.setResultsWidget(None)

他の解説このアプローチなど欠点は落とし穴"との声など) りますようお願い申し上げます。

分解能:

その結のQThreadクラスおよび関連する信号スロット間の通信にスレッド)。これは主に私のプログラムが既に使用Qt/PyQt4のためのGUIオ/トセット。このソリューションも少し変わっ既存のコードを実行します。

こちらのリンクを適用Qt品について説明Qt取り扱うスレッド信号 http://www.linuxjournal.com/article/9602.を抜粋した。

幸いなことに、Qt許可 信号スロットに接続する 横糸としてのスレッド 実行中のそれぞれ固有のイベントタイルです。このしくみは、洗浄方法 通信に比べて送信および 受信イベントがされることを回避することができ すべての帳簿および中間体 QEvent由来の授業となる 必要な任意の自明でな 願います。コミュニケーション スレッドになりますの 接続からの信号を一つのスレッド のスロットが別のmutexing ンドの安全性の問題の交換 データとスレッドの取扱い Qt.

がなぜ必要なの走行イベント ループ内の各スレッドで い信号?その理由 の間のスレッド 通信機構の使用によるQt 接続する場合はからの信号を一 スレッドのスロット別のスレッドの.そのような接続がで とクリーンエアー、窒素、ヘリウム接続します。時信号の排出されるよ キューに接続では、スロットが呼び出されます 次回は、先のオブジェクトの イベントのループが実行されます。場合にスロット たのではなくて呼び出された直接 信号から別のスレッドは、スロット うに実行し、同じコンテキストとして ッドは、呼び出し側スレッド.通常、これは あなたに何をしたい(特にない したいものをご利用の場合 データベース接続は、データベース 接続が利用できるのは、 スレッドが作成されます。のキュー 接続を適切に派遣し、 信号のスレッドオブジェクト を呼び出し、スロットに独自のコンテキスト ピギー-バッキングのイベントシステム。それでは、こうありたい スレッド間のコミュニケーション 一部のスレッドの取扱い データベースに接続します。Qt 信号スロット機構でのルートは、 実装はスレッド間の イベントのパススキームは、上記 がクリーン でき、より使いやすいインタフェース。

注意: eliben も良い答えは、まず利用PyQt4取り扱っているスレッドの安全性とmutexing、解決されていった。

役に立ちましたか?

解決

あなたが本当にPythonのスレッドモジュールからのPyQtのQThreadクラスの代わりに、Threadクラスを使用する必要があり、その後、メインスレッドへの進捗状況を示すための信号を使用する場合。

QThread、シグナルとスロットを使用する単純な例では、PyQtはウィキで見つけることができる:

https://wiki.python.org/moin/PyQt/Threading,_Signals_and_Slots

他のヒント

あなたはキューのget()でブロックする必要があるため、ネイティブのpythonキューが動作しません、それはあなたのUIをアップバング。

Qtは、本質的にクロススレッド通信の内側にキューイング・システムを実装します。スロットへの呼び出しを投稿する任意のスレッドからこのコールをしてみます。

QtCore.QMetaObject.invokeMethod()

これは不格好だと不十分な文書化されているが、それは、あなたも非Qtのスレッドからから欲しいものを行う必要があります。

また、このためにイベントの機械を使用することができます。 「ポスト」のようなものをという名前のメソッドにはQApplication(またはQCoreApplication)を参照してください。

編集:ここでは、より完全な例です...

私はQWidgetのに基づいて自分のクラスを作成しました。これは、文字列を受け取りスロットを持っています。私はこのようにそれを定義します:

@QtCore.pyqtSlot(str)
def add_text(self, text):
   ...

その後、私は、メインのGUIスレッドでこのウィジェットのインスタンスを作成します。メインのGUIスレッドまたは他のスレッドから(木材をノック)私が呼び出すことができます:

QtCore.QMetaObject.invokeMethod(mywidget, "add_text", QtCore.Q_ARG(str,"hello world"))

不格好が、それはそこにあなたを取得ます。

ダンます。

私はあなたの代わりに、シグナリングのキューを使用することをお勧めします。それはより多くの同期ですので、個人的に私は、プログラミングのことはるかに堅牢で理解しやすい方法を見つけます。

スレッドがキューから「仕事」を取得し、別のキューに結果を戻す必要があります。さらに第3のキューがエラーと「経過報告」のような通知やメッセージ、のためのスレッドで使用することができます。あなたのコードをこのように構造化すると、それが管理することが非常に簡単になります。

このように、単一の「ジョブキュー」と「結果キュー」はまた、それがメインGUIスレッド内経路、ワーカースレッドのグループによってスレッドからの全ての情報を使用することができる。

ご方法"processDoc"なの変更その他のデータで見のためのデータの一部を返送しな変化変数または財産の親クラスに使用Py_BEGIN_ALLOW_THREADSとPy_END_ALLOW_THREADS macroses( 詳しくはこちら にします。では、文書処理されますのスレッドなロックの通訳およびUIコンテンツは更新されます。

あなたはいつもPythonで、この問題を持ってしようとしています。 GoogleのGIL以上の背景について、「グローバル通訳ロック」。使用ツイストに、またはモジュールを使用する:あなたが経験している問題を回避するには、2つの一般的に推奨される方法があります。同様 2.5で導入するモジュールマルチプロセッシング

ツイストは、あなたが最初に混乱するかもしれませんが、あなたは、高スループットのネットワークアプリケーションを記述する必要があると長い目で見ればより有益である場合には参考になると非同期プログラミング技術を習得することを要求されます。

マルチプロセッシングモジュールは、新しいプロセスをforkし、あなたが本当のスレッドを持っていたかのように動作させるためにIPCを使用します。唯一の欠点は、あなたが、デフォルトでは、ほとんどのLinuxディストリビューションやOSXに含ま「かなり新しいと研でインストールのpython 2.5が必要になるということです。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top