2016-03-26 163 views
1

我有一個python GUI程序需要執行相同的任務,但有幾個線程。問題是我調用線程,但它們不會並行執行,而是按順序執行。第一個執行,結束,然後第二個,等等。我希望他們獨立開始。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或「啓動過程」,gui被鎖定,直到兩個線程完成執行。 這個想法是,線程應該在後臺工作,並行工作。

回答

2

使用類作爲線程的target的一種方法是將該類用作目標,並將構造函數的參數用作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

不完全精確,'螺紋(目標=無)。開始()'是完全有效的,更何況在物體上的方法是可調用的,所以初始化它然後在線程中運行該方法沒有任何問題。 –

+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