2013-05-03 15 views
-2

我需要幫助與Python項目:如何將Python方法作爲子進程運行?

例子:

class MyFrame(wx.Frame): 
    def __init__(self, parent, title):  
     super(MyFrame, self).__init__(parent, title=title, size=(330, 300)) 
     self.InitUI() 
     self.Centre() 
     self.Show() 

    def InitUI(self): 
     """ 
     Subprocess 
     """ 
     subprocess.execMethodFromClass(self , 'Connection' , args1 , args2 , ...) 

    def Connection(self): 
     self.connection = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
     self.connection.connect(('192.0.1.135' , 3345)) 
     while True: 
      data = self.connection.recv(1024) 
      if not data: 
       break 
      else: 
       print data 

顯示:

subprocess.execMethodFromClass(self , 'Connection' , args1 , args2 , ...) 

謝謝!

+2

請多花點心思來解釋你的問題! – Moj 2013-05-03 18:06:57

+1

你可能想在後臺*線程*(而不是子進程)中運行'Connection'並使用'wx.CallAfter()'向主線程(GUI)報告結果(參見[長時間運行的任務wiki] wiki.wxpython.org/LongRunningTasks))。 – jfs 2013-05-04 14:45:34

回答

2

隨着友好dogcow說,在子進程中運行的功能,所有你需要做的正在使用multiprocessing.Process

p = multiprocessing.Process(target=f, args=('bob',)) 
p.start() 
p.join() 

當然,您可能想要在大多數*現實生活中使用的情況下,仍然會使用pjoin。你顯然沒有通過產生一個新的過程來獲得任何平行度,只是爲了讓你的主要過程坐下來等待。

所以,你的情況,這只是:

p = multiprocessing.Process(target=self.Connection, args=(args1, args2)) 

但是這可能不會工作你的情況,因爲你想調用的方法當前self對象。

首先,根據您的平臺和Python版本,multiprocessing可能必須通過酸洗和通過管道發送綁定方法self.Connection給孩子。這涉及酸洗self實例以及該方法。所以它只會在MyFrame對象被pickleable時才起作用。我很確定wx.Frame不能被醃製。

即使你得到self對象的孩子,這顯然會副本,而不是一個共享實例。所以,當子進程的Connection方法設置爲self.connection = …時,這不會影響原始父進程的self

如果您嘗試調用任何wx.Frame方法會更糟糕。即使所有的Python工作都在大多數平臺上工作,但試圖從錯誤的進程中修改GUI資源(如Windows)將不起作用。

您實際可以共享的唯一對象種類是您可以放入multiprocessing.Valuemultiprocessing.sharedctypes的種類。


解決這個問題的辦法是分解出要childify到一個單獨的,孤立的函數的代碼,這股儘量少(最好什麼都沒有,或者只是一個Queue or Pipe)與父。

對於你的榜樣,這是很容易:

class Client(object): 
    def connect_and_fetch(self): 
     self.connection = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 
     self.connection.connect(('192.0.1.135' , 3345)) 
     while True: 
      data = self.connection.recv(1024) 
      if not data: 
       break 
      else: 
       print data 

def do_client(): 
    client = Client() 
    connect_and_fetch() 

class MyFrame(wx.Frame): 
    # ... 
    def Connection(self): 
     self.child = multiprocessing.Process(target=do_client) 
     self.child.start() 
    # and now put a self.child.join() somewhere 

事實上,你甚至不需要一個類的都在這裏,因爲你必須爲self的唯一用途是存儲變量,可以很就像當地人一樣容易。但我在你的現實生活節目中猜測,還有更多的狀態。

wxpython wiki上有一個有趣(如果有點過時)的例子,稱爲MultiProcessing,它看起來像它做你想要什麼和更多。 (這是根據classmethod子進程,而不是由於某種原因,一個獨立的功能,並使用舊式的語法,因爲它是老了,但我希望它仍然是有幫助的。)


如果您使用wx對於您的GUI,您可能需要考慮使用其進程間機制,而不是本機Python。儘管在一般情況下它比較複雜且較不pythonic,但當您嘗試將子流程和通信管道集成到主事件循環中時,爲什麼不讓wx處理它?

另一種方法是創建一個線程以等待子進程和/或其他任何PipeQueue您給它,然後創建並將wx.Event s發佈到主線程。


*大多數不是全部。例如,如果f暫時耗盡大量內存,則在子進程中運行它意味着儘可能快地將該內存釋放到操作系統。或者,如果它稱不好的第三方/遺留/任何具有令人討厭且文檔記錄不完整的全球副作用的代碼,則您將與這些副作用隔離開來。等等。

1

http://docs.python.org/dev/library/multiprocessing.html

from multiprocessing import Process 

def f(name): 
    print('hello', name) 

if __name__ == '__main__': 
    p = Process(target=f, args=('bob',)) 
    p.start() 
    p.join() 
+0

但他想在'self'上運​​行一個方法,而不是模塊級別的函數。我不認爲新手可以弄清楚如何從這裏到達那裏。特別是因爲在他的情況下,即使他確實搞清楚了,也不行。 – abarnert 2013-05-03 19:10:05

1

你不能。您可以使用子進程調用另一個應用程序或腳本以在單獨的進程中運行。

subprocess.Popen(cmds) 

如果您需要運行一些長時間運行的進程,請查看線程或多處理模塊。這裏有一些鏈接:

相關問題