9

グラフィカルアプリケーションでマルチスレッドを使用する必要性についての適切な説明を探しています。以下の例ではPythonが使用されていますが、質問はPython固有ではなく、任意の言語でのグラフィカルプログラミングの一般的な設計に当てはまります。

簡単な例を見てみましょう。ファイルのコレクションに対してある種の時間のかかる操作を実行し、その進行状況をコンソールに出力するアプリケーションがあると仮定します。この操作にはファイルごとに2秒かかり、1.txt、2.txt、3.txt、...10.txtという名前の10個のファイルを処理するとします。次に、実装例は次のようになります。

コンソール

import time
def process(file):
    print 'processing {0}...'.format(file)
    time.sleep(2.0) #simulate slow operation

files = ['{0}.txt'.format(i) for i in range(1, 11)]
map(process, files)

コンソールの例はもちろんシングルスレッドであり、問​​題なく機能します。ここで、グラフィカルなプログレスバーを追加する場合、シングルスレッドの実装は次のようになります。

シングルスレッドのGUI

import time, gtk, gobject

def process(file):
    print 'processing {0}...'.format(file)
    time.sleep(2.0)

class MainWindow(gtk.Window):
    def __init__(self):
        super(MainWindow, self).__init__()
        self.progress = gtk.ProgressBar()
        self.progress.set_fraction(0)
        self.add(self.progress)
        self.connect("destroy", gtk.main_quit)
        self.show_all()
        files = ['{0}.txt'.format(i) for i in range(1, 11)]
        gobject.timeout_add(100, self.submit, files, 0)

    def submit(self, files, i):
        process(files[i])
        self.progress.set_fraction((i + 1.0)/len(files))
        if i + 1 < len(files):
            gobject.idle_add(self.submit, files, i + 1)

win = MainWindow()
gtk.main()

これは正常に機能しているように見えますが、たとえばウィンドウのサイズを変更してみるなど、アプリケーションを実行しようとすると、スタックし、保留中のGUIイベントを処理するために解放されたときに2秒ごとにのみ応答します。最後の例はマルチスレッドの実装であり、実行中ずっと応答性を維持します。

マルチスレッドGUI

import time, gtk, gobject, threading

def process(file):
    print 'processing {0}...'.format(file)
    time.sleep(2.0)

class MainWindow(gtk.Window):
    def __init__(self):
        super(MainWindow, self).__init__()
        self.progress = gtk.ProgressBar()
        self.progress.set_fraction(0)
        self.add(self.progress)
        self.connect("destroy", gtk.main_quit)
        self.show_all()
        files = ['{0}.txt'.format(i) for i in range(1, 11)]
        threading.Thread(target=self.submit, args=(files,)).start()

    def submit(self, files):
        for i, file in enumerate(files):
            process(file)
            gobject.idle_add(self.progress.set_fraction, (i + 1.0)/len(files))
            if not self.get_visible():
                return

gtk.gdk.threads_init()
win = MainWindow()
gtk.main()

コードに長時間実行されるブロッキング操作があり、マルチスレッドソリューションを使用する必要があるレスポンシブGUIが必要な場合は、完全に明確で論理的に思えます。それを回避する他の方法はありません。これは本当ですか?私はこれを他の開発者に何度も説明しようとしましたが、多くの人は理解していないか、同意していません。誰かがこの概念の説明、それに関する記事へのリンクを提供することができますか、または私の理解が間違っている場合は私を訂正できますか?

4

3 に答える 3

8

あなたの理解は正しいです。アプリケーションがマルチスレッド化されていない場合、アプリケーションはすべての操作が完了するまで待機します。アプリケーションがマルチスレッドの場合、1 つのスレッドを使用して GUI アクションを処理し、別のスレッドを使用してファイルを処理します。

記事や同様のものへの参照はありません。スレッドを人間と考えてください。それぞれに独自の仕事があり、一度に 1 つのことしか実行できません。

于 2012-11-12T11:50:14.883 に答える
3

主な理由は、GUIツールキットがでのすべてのイベント(マウスの動き、ボタンのクリック、キーボード入力、システムイベントなど)をmainloop処理することです。これは、GUIアプリケーション用に作成したコードの一部ではありません。

このメインループは、提供するすべてのイベントハンドラーとその他の関数を呼び出します。現在、これらの関数の1つに時間がかかりすぎる場合(たとえば、100ミリ秒を超える場合)、メインループがそれ以上のイベントを処理できないため、UIの応答性に非常に顕著な影響があります。

このトピックについては、使用するツールキットのプログラミング言語に関係なく、GUIプログラミングに関する書籍の「高度な概念」セクションで詳しく説明する必要があります。

于 2012-11-12T12:13:52.313 に答える
0

Multithreading is one way of approaching this, but not necessarily the only (or best) way. As a python example, greenlets provide a way of running concurrent processes within the same thread, avoiding the problems with locking associated with multithreading. I would certainly consider greenlets to be a preferred solution in most cases simply because of the relative ease of coding them.

于 2012-11-12T11:56:04.490 に答える