2016-03-26 3 views
1

私は同じタスクを実行する必要があるいくつかのスレッドを持つPython GUIプログラムを持っています。問題は、私はスレッドを呼び出すが、それらは並列ではなく逐次実行することである。最初のものが実行され、それが終了し、次に2番目のものなどがあります。Python GUIは、スレッドコードの実行が完了するのを待っている間にフリーズしています

主なコンポーネントは次のとおりです。
1.メニュー(ビュー)
2. ProcesStarter(コントローラ)
3.プロセス(コントローラ)あなたは、 "スタート" をクリックしてどこ

メニューがあります機能を呼び出すボタンProcesStarter

ProcesStarterプロセスのオブジェクトとスレッドを作成し、forループ内のすべてのスレッドを開始します。

メニュー:

class VotingFrame(BaseFrame): 

    def create_widgets(self): 
    self.start_process = tk.Button(root, text="Start Process", command=lambda: self.start_process()) 
    self.start_process.grid(row=3,column=0, sticky=tk.W) 

    def start_process(self): 
    procesor = XProcesStarter() 
    procesor_thread = Thread(target=procesor.start_process()) 
    procesor_thread.start() 

ProcesStarter

class XProcesStarter: 

    def start_process(self): 
     print "starting new process..." 

     # thread count 
     thread_count = self.get_thread_count() 

     # initialize Process objects with data, and start threads 
     for i in range(thread_count): 
      vote_process = XProcess(self.get_proxy_list(), self.get_url()) 
      t = Thread(target=vote_process.start_process()) 
      t.start() 

プロセス:

class XProcess(): 

    def __init__(self, proxy_list, url, browser_show=False): 
     # init code 

    def start_process(self): 
     # code for process 

私は、GUIのボタンFを押すとまたは "Start Process"を実行すると、両方のスレッドが実行を終了するまでGUIがロックされます。 スレッドはバックグラウンドで動作し、並列に動作するはずです。

答えて

2

スレッドのtargetとしてクラスを使用する方法の1つは、クラスをターゲットとして使用し、コンストラクタへの引数をargsとして使用することです。

from threading import Thread 
from time import sleep 
from random import randint 

class XProcesStarter: 
    def __init__(self, thread_count): 
    print ("starting new process...") 
    self._i = 0 
    for i in range(thread_count): 
     t = Thread(
     target=XProcess, 
     args=(self.get_proxy_list(), self.get_url()) 
    ) 
     t.start() 


    def get_proxy_list(self): 
    self._i += 1 
    return "Proxy list #%s" % self._i 

    def get_url(self): 
    self._i += 1 
    return "URL #%d" % self._i 

class XProcess():  
    def __init__(self, proxy_list, url, browser_show=False): 
    r = 0.001 * randint(1, 5000) 
    sleep(r) 
    print (proxy_list) 
    print (url) 

def main(): 
    t = Thread(target=XProcesStarter, args=(4,)) 
    t.start() 

if __name__ == '__main__': 
    main() 

このコードはpython2とpython3で動作します。

なぜなら、Threadオブジェクトのターゲットは呼び出し可能でなければならないからです(完全な説明については、pythonのドキュメントで "callable"と "__call__"を検索してください)。

他の方法は他の人の回答(Tadhg McDonald-Jensen参照)で説明されています。

+2

完全に正確ではない、 'スレッド(ターゲット=なし).start()'完全に有効である、言及しないように、そのオブジェクトのメソッド呼び出し可能なので、最初に初期化してからスレッド内でメソッドを実行することに何も問題はありません。 –

+1

ありがとう!私は今日何かを学んだ! (私も私の答えを編集します) –

+0

これにコードが変更され、期待どおりに動作しています! – nullwriter

3

スレッドのターゲットとしてそれを指定するときは、すぐにprocesor.start_process()を呼び出す:

#use this 
procesor_thread = Thread(target=procesor.start_process) 

#not this 
procesor_thread = Thread(target=procesor.start_process()) 
          # this is called right away^

をあなたはすぐにそれを呼び出す場合は、スレッドの有効なターゲットであるNoneを返す(それだけで何もしない)理由でありますそれは順次発生し、スレッドは何もしていません。

+0

これは実際には@Sci Progの答えよりも速く編集されたでしょう。しかし、私は今なぜ理解しますか: – nullwriter

2

あなたの問題は、スレッドを開始する両方の場所で、実際にはtargetとしてスレッドに渡すメソッドを呼び出すことだと思います。これは、メインスレッドでコードを実行します(戻り値があれば、新しいスレッドを開始します)。

試してみてください。

procesor_thread = Thread(target=procesor.start_process) # no() after start_process 

そして:

t = Thread(target=vote_process.start_process) # no() here either 
+0

ありがとう、それを今取得します。 'target = procesor.start_process()'と言うだけで、なぜそれがまっすぐに呼ばれていたのか、自分自身に尋ねていました。 – nullwriter