2012-06-07 51 views
1

的Python 2.7.3 64 wxPython的2.8 x64的wxPython非阻塞GUI線程和多處理?

一直在閱讀關於Python線程和多,特別是一些由道格·海爾曼,已經極大地幫助文章頗有幾分。不過,我很困惑的一件事......

認爲 Python的多模塊更或多或少的下降,在更換爲線程模塊,除此之外,ARGS必須picklable,但我m發現爲了不阻止我的GUI,我必須首先用threading創建一個新線程。然後在該線程中使用multiprocessing.Process線程進行多線程。這工作,並運作良好,但它似乎有點kludgey給我。

如果我嘗試在沒有第一次線程的情況下直接進行多進程,那麼我的GUI仍會阻塞,直到多處理作業完成。這是按照設計工作的,還是我錯過了關於多處理模塊的基本知識?

如果需要示例,我可以提供它們。

謝謝,

-RMWChaos

請求一個例子...

假設onProcess()由在GUI的按鈕觸發,則該塊中的GUI ...

import time 
import multiprocessing as mp 

def myWorker(a, b): 
    time.sleep(0.1) 
    print '{} * {} = {}'.format(a, b, a*b) 

def onProcess(event): 
    jobs = mp.cpu_count() * 2 
    a = 5 
    b = 10 

    for job in range(jobs): 
     mp.Process(target = myWorker, args = (a, b,)).start() 

雖然這並不...

import time 
import multiprocessing as mp 
import threading as th 

def myWorker(a, b): 
    time.sleep(0.1) 
    print '{} * {} = {}'.format(a, b, a*b) 

def onProcess(event): 
    a = 5 
    b = 10 
    th.Thread(target = myThread, args = [a, b,]).start() 

def myThread(a, b): 
    jobs = mp.cpu_count() * 2 

    for job in range(jobs): 
     mp.Process(target = myWorker, args = (a, b,)).start() 
+0

也許你應該添加一個小例子來描述你的問題。 – Amr

回答

5

多線程和多處理從根本上是不同的。

線程大部分用於I/O。當你創建一個新的線程時,它被包含在與你創建線程的程序相同的進程中。這意味着它與程序共享內存空間,但它們(程序和線程)不能並行運行(也可以查看GIL)。

另一方面,多處理在OS級別上產生新的進程。這個新進程可以與預先存在的進程並行運行,但它不會與產生它的程序共享內存空間。當你想要加速的代碼不是I/O相關的,而是實際的處理器密集型計算時,這更有用。

對於gui來說,你大多希望對gui的不同部分使用線程,以便在gui的一部分中運行某些東西不會鎖定整個gui,直到處理結束。沒有代碼很難說,但我相信你不應該特別需要在新線程中產生一個進程,而只是讓那個線程處理處理。但是,如果該線程需要處理大量計算類型的處理而不是大量的I/O,那麼您將需要啓動一個進程來處理該進程。

我相信你的大部分問題在於誤解多處理和多線程。

+0

我認爲這回答了這個問題。基本上,我希望計算密集型和I/O密集型進程在後臺運行而不會阻塞GUI。這告訴我,我需要同時執行這兩種操作 - 線程化以便GUI不被阻塞,並且需要多處理來將工作負載分散到多個內核中。 – RMWChaos

+0

你正在尋找的是多線程。產生一個新的線程來處理事件,這應該解決阻塞gui其餘部分的問題。 此外,您可能想要生成一個進程來處理線程內部的處理,但這更多的是設計和特定問題。 – forTruce

+0

或多或少像我上面提供的第二個例子? – RMWChaos

1

我試圖運行你的代碼在下面的測試程序和多工作正常,沒有什麼阻止:

import time 
import multiprocessing as mp 
import wx 


def myWorker(a, b): 
    time.sleep(10) 
    print '{} * {} = {}'.format(a, b, a*b) 

def onProcess(event): 
    jobs = mp.cpu_count() * 2 
    a = 5 
    b = 10 

    for job in range(jobs): 
     mp.Process(target = myWorker, args = (a, b,)).start() 

def onGUI(event): 
    print 'GUI is not blocked' 

class MyFrame(wx.Frame): 
    def __init__(self, parent, id, title): 
     wx.Frame.__init__(self, parent, id, title) 
     buttons = [] 
     panel = wx.Panel(self, wx.ID_ANY) 
     sizer = wx.BoxSizer(wx.VERTICAL) 
     gui_proc_btn = wx.Button(panel, wx.ID_ANY, 'GUI Process') 
     other_proc_btn = wx.Button(panel, wx.ID_ANY, 'Other process') 

     gui_proc_btn.Bind(wx.EVT_BUTTON, onGUI) 
     sizer.Add(gui_proc_btn, 0, wx.ALL, 5) 
     other_proc_btn.Bind(wx.EVT_BUTTON, onProcess) 
     sizer.Add(other_proc_btn, 0, wx.ALL, 5) 
     panel.SetSizer(sizer) 

class MyApp(wx.App): 
    def OnInit(self): 
     frame = MyFrame(None, -1, 'test.py') 
     frame.Show(True) 
     self.SetTopWindow(frame) 
     return True 

if __name__ == '__main__': 

    app = MyApp(0) 
    app.MainLoop() 

運行該從你的命令行,按第二個按鈕(你的函數這使用multiprocessing,我增加了睡眠時間),然後按第一個按鈕。 你應該注意到當按下第一個按鈕時會產生輸出,所以程序沒有被阻塞。

+0

將會生成輸出,但在背景mp進程運行時嘗試移動GUI,並且會收到「Not Responding」消息 - 至少在Windows 。實際上,使用上面的代碼,它產生了許多新的GUI,並且直到我全部關閉它們之後纔會輸出到控制檯。根據Windows處理多處理的方式,該行爲可能是特定於操作系統的;所以如果你在Linux上運行,你可能會看到不同的結果。謝謝! – RMWChaos

+0

是的,我在Linux上。 Windows沒有分叉,所以多處理試圖將整個程序複製到內存中,也許這就是爲什麼你最終擁有多個窗口的原因。 – Amr

+0

糟糕,我的壞。查看多處理[文檔](http://docs.python.org/library/multiprocessing.html)在Windows上需要添加'if __name__ =='__main __'',請嘗試立即運行代碼。 – Amr