如何将Python方法作为子进程运行?

时间:2013-05-03 17:40:16

标签: python multithreading wxpython pthreads subprocess

我需要一个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 , ... )

谢谢!

3 个答案:

答案 0 :(得分:2)

正如友善的狗狗所说,要在儿童过程中运行一项功能,您所要做的就是使用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个对象可以选择时它才有效。我很确定wx.Frame无法被腌制。

即使你得到孩子的self对象,它显然也是副本,而不是共享实例。因此,当子流程的Connection方法设置self.connection = …时,这不会影响原始父流程的self

如果您尝试调用任何wx.Frame方法,情况会更糟。即使所有的Python工作都有效,在大多数平台上,尝试从错误的进程中修改窗口等GUI资源也行不通。

您可以实际分享的唯一对象类型是您可以放入multiprocessing.Valuemultiprocessing.sharedctypes的种类。


解决这个问题的方法是将你想要子化的代码分解为一个独立的,孤立的函数,它与父元素尽可能少地共享(理想情况下没有,或只有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代替独立函数,并使用旧式语法,因为它已经过时了,但希望它仍然有用。)


如果您在GUI中使用wx,则可能需要考虑使用其进程间机制而不是本机Python机制。虽然在一般情况下它更复杂,更少pythonic,但当您尝试将子进程及其通信管道集成到主事件循环中时,为什么不让wx来处理它?<​​/ p>

另一种方法是创建一个线程来等待子进程和/或你给它的任何PipeQueue,然后创建并发布wx.Event到主线程


*大多数,不是全部。例如,如果f暂时耗尽了大量内存,则在子进程中运行它意味着您可以尽快将该内存释放到操作系统。或者,如果它称为写得不好的第三方/遗产/任何具有令人讨厌且记录不良的全球副作用的代码,那么您就会与这些副作用隔离开来。等等。

答案 1 :(得分: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()

答案 2 :(得分:1)

你做不到。您可以使用子进程调用另一个应用程序或脚本以在单独的进程中运行。

subprocess.Popen(cmds)

如果需要运行一些长时间运行的进程,请查看线程或多处理模块。以下是一些链接: