0

作業中のプログラムで別の問題が発生しました。基本的に、私のプログラムは最大 4 つの入力ファイルを受け取り、それらを処理し、それらから収集した情報をコンピューターの SQLite3 データベースに保存します。これにより、入力ファイルを再度実行しなくても、いつでもデータを表示できるようになりました。このプログラムは、基本的に入力スクリプトをインポートする AUI Notebook であるメイン スクリプトと、パネルとして使用する出力スクリプトを使用します。

データベースにデータを追加するには、結果を出力画面に直接返さないため、スレッドを使用できます。ただし、メイン テーブルの内容全体を表示する必要がある場合、25,000 レコードが読み込まれることになります。これらがロードされている間、私の GUI はロックされ、ほとんど常に「プログラムが応答しません」と表示されます。

スレッド化/マルチプロセッシングを使用してデータベースから 25k レコードを取得し、それらを ObjectListView ウィジェットにロードして、このプロセス中に GUI を使用できるようにしたいと考えています。データベースにデータを追加するために使用される同様のスレッド クラスを使用しようとすると、何も返されません。何も得られないと言っても過言ではありません。

これが私の大きな質問です。グローバル変数を使用せずにクエリをスレッド化して結果を返す方法はありますか? 理解できる例で解決策を見つけることができませんでしたが、間違った検索用語を使用している可能性があります。

当面の問題に関連するコードのスニペットを次に示します。

これは、データが ObjectListView ウィジェットの準備ができていることを確認するために使用するものです。

class OlvMainDisplay(object):
    def __init__(self, id, name, col01, col02, col03, col04, col05,
                 col06, col07, col08, col09, col10, col11,
                 col12, col13, col14, col15):
        self.id    = id
        self.name  = name
        self.col01 = col01
        self.col02 = col02
        self.col03 = col03
        self.col04 = col04
        self.col05 = col05
        self.col06 = col06
        self.col07 = col07
        self.col08 = col08
        self.col09 = col09
        self.col10 = col10
        self.col11 = col11
        self.col12 = col12
        self.col13 = col13
        self.col14 = col14
        self.col15 = col15

データを取得している2つのテーブル:

class TableMeta(base):
    __tablename__ = 'meta_extra'
    id = Column(String(20), ForeignKey('main_data.id'), primary_key=True)
    col06 = Column(String)
    col08 = Column(String)
    col02 = Column(String)
    col03 = Column(String)
    col04 = Column(String)
    col09 = Column(String)
    col10 = Column(String)
    col11 = Column(String)
    col12 = Column(String)
    col13 = Column(String)
    col14 = Column(String)
    col15 = Column(String)


class TableMain(base):
    __tablename__ = 'main_data'
    id    = Column(String(20), primary_key=True)
    name  = Column(String)
    col01 = Column(String)
    col05 = Column(String)
    col07 = Column(String)

    extra_data = relation(
        TableMeta, uselist=False, backref=backref('main_data', order_by=id))

これら 2 つのテーブルから収集するために 2 つのクエリを使用します。1 つはすべてのレコードを取得し、もう 1 つは複数の辞書を取り、辞書の内容に基づいてフィルターを適用する関数定義の一部です。両方のクエリは、各ノートブック パネルによってインポートされるメインの「ワーカー」スクリプトの一部です。

フィルターを適用する関数は次のとおりです。

def multiFilter(theFilters, table, anOutput, qType):
    session = Session()
    anOutput = session.query(table)
    try:
        for x in theFilters:
            for attr, value in x.items():
                anOutput = anOutput.filter(getattr(table, attr).in_(value))
    except AttributeError:
        for attr, value in theFilters.items():
            anOutput = anOutput.filter(getattr(table, attr).in_(value))

    anOutput = convertResults(anOutput.all())
    return anOutput
    session.close()

theFilters は、単一の辞書または辞書のリストのいずれかにすることができるため、"Try:" ステートメントが使用されます。関数がフィルタを適用すると、返された結果を別の関数で実行します。この関数は、OlvMainDisplay クラスから返された各結果を配置し、それらをリストに追加して OLV ウィジェットに渡します。

ここでも大きな問題ですが、グローバル変数を使用せずにクエリ (または複数のクエリ) をスレッド化し、結果を返す方法はありますか? または、一度に約 200 レコードを取得して、データを「チャンク単位で」OLV ウィジェットに追加することはできますか?

前もって感謝します。
-マイクS

--UPDATE-- 「Python でスレッドから戻り値を取得する方法」
を確認しましたが、受け入れられた回答は何も返さないか、GUI をロックしたままです (差異の原因がわからない)。作成するスレッドの数は最大で 5 つ程度に制限したいと考えています。

--New Update-- フィルター機能を一部修正しました。

4

2 に答える 2

1

おそらく、データベース全体を一度にメモリにロードしたくないでしょう。それは通常悪い考えです。ObjectListView は ListCtrl のラッパーであるため、基になるウィジェットの仮想バージョンを使用することをお勧めします。フラグは wx.LC_VIRTUAL です。例として wxPython デモを見てみましょう。基本的には、仮想メソッド OnGetItemText()、OnGetItemImage()、および OnGetItemAttr() を介してオンデマンドでデータをロードします。これは ListCtrl メソッドを参照していることに注意してください...OLV ランドでは異なる場合があります。とにかく、OLV バージョンは VirtualObjectListView と呼ばれ、ほとんど同じように機能することを知っています。ソースのダウンロードに例があると確信しています。

于 2013-11-11T19:30:18.593 に答える
0

ようやくクエリをスレッドで実行し、結果を標準の ObjectListView に表示できるようになりました。ここでいくつかの変更を加え て回答を使用しました。

出力パネルにEWとしてインポートされるメイン ワーカー スクリプトにコードを追加しました。
クエリに引数を渡していないため、これらの行が変更されました。

    def start(self, params):

    self.thread = threading.Thread(target=self.func, args=params)

    def start(self):

    self.thread = threading.Thread(target=self.func)

出力パネルで、25,000 件以上のレコードを返すデフォルトのクエリを呼び出す方法を変更しました。出力パネルの initで、プレースホルダーとしてself.worker = ()を追加し、デフォルトのクエリを実行する関数に追加しました。

def defaultView(self, evt):
    self.worker = EW.ThreadWorker(EW.defaultQuery)
    self.worker.start()
    pub.sendMessage('update.statusbar', msg='Full query started.')

私も追加しました:

def threadUpdateOLV(self):
    time.sleep(10)
    anOutput = self.worker.get_results()
    self.dataOLV.SetObjects(anOutput)

pub.subscribe(self.threadUpdateOLV, 'thread.completed')

time.sleep(10)は試行エラーの後に追加され、25,000 件以上の完全な結果が得られました。10 秒の遅延で問題なく動作することがわかりました。

最後に、デフォルト クエリの最後に、出力が返される直前に PubSub 送信を追加しました。

wx.CallAfter(pub.sendMessage, 'thread.completed')
return anOutput
session.close()

正直なところ、これを達成するためのより良い方法があると確信していますが、現時点では必要な目的を果たしています. 私はより良い解決策を見つけることに取り組みます。

ありがとう
-マイク S

于 2013-11-26T20:03:29.190 に答える