Python:使用线程多次调用subprocess.Popen

时间:2009-08-10 15:11:11

标签: python

我有一个正在运行的服务(Twisted jsonrpc服务器)。当我调用“run_procs”时,服务将查看一堆对象并检查它们的timestamp属性以查看它们是否应该运行。如果它们应该,它们会被添加到thread_pool(列表)中,然后thread_pool中的每个项都会获得调用的start()方法。

我已经将这个设置用于其他几个应用程序,我希望在我的类中使用theading运行一个函数。但是,当我在每个线程调用的函数中使用subprocess.Popen调用时,调用一次一个地运行,而不是像我期望的那样同时运行。

以下是一些示例代码:

class ProcService(jsonrpc.JSONRPC):
        self.thread_pool = []
        self.running_threads = []
        self.lock = threading.Lock()

        def clean_pool(self, thread_pool, join=False):
                for th in [x for x in thread_pool if not x.isAlive()]:
                        if join: th.join()
                        thread_pool.remove(th)
                        del th
                return thread_pool

        def run_threads(self, parallel=10):
                while len(self.running_threads)+len(self.thread_pool) > 0:
                        self.clean_pool(self.running_threads, join=True)
                        n = min(max(parallel - len(self.running_threads), 0), len(self.thread_pool))
                        if n > 0:
                                for th in self.thread_pool[0:n]: th.start()
                                self.running_threads.extend(self.thread_pool[0:n])
                                del self.thread_pool[0:n]
                        time.sleep(.01)
                for th in self.running_threads+self.thread_pool: th.join()

        def jsonrpc_run_procs(self):
                for i, item in enumerate(self.items):
                        if item.should_run():
                                self.thread_pool.append(threading.Thread(target=self.run_proc, args=tuple([item])))
                self.run_threads(5)

        def run_proc(self, proc):
                self.lock.acquire()
                print "\nSubprocess started"
                p = subprocess.Popen('%s/program_to_run.py %s' %(os.getcwd(), proc.data), shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE,)
                stdout_value = proc.communicate('through stdin to stdout')[0]
                self.lock.release()

感谢任何帮助/建议。

*编辑* 好。所以现在我想读回stdout管道的输出。这在某些时候会起作用,但也会因select.error而失败:(4,'中断系统调用')我认为这是因为有时在我尝试运行通信方法之前,进程已经终止。 run_proc方法中的代码已更改为:

def run_proc(self,proc):     self.lock.acquire()     p = subprocess.Popen(#etc     self.running_procs.append([p,proc.data.id])     self.lock.release()

在我调用self.run_threads(5)之后我调用self.check_procs()

check_procs方法迭代running_procs列表以检查poll()是否为None。如何从管道输出?我试过以下两个

calling check_procs once:

def check_procs(self):
    for proc_details in self.running_procs:
        proc = proc_details[0]
        while (proc.poll() == None):
            time.sleep(0.1)
        stdout_value = proc.communicate('through stdin to stdout')[0]
        self.running_procs.remove(proc_details)
        print proc_details[1], stdout_value
        del proc_details

calling check_procs in while loop like:

while len(self.running_procs) > 0:
    self.check_procs()

def check_procs(self):
    for proc_details in self.running_procs:
        if (proc.poll() is not None):
            stdout_value = proc.communicate('through stdin to stdout')[0]
            self.running_procs.remove(proc_details)
            print proc_details[1], stdout_value
            del proc_details

2 个答案:

答案 0 :(得分:1)

我认为关键代码是:

    self.lock.acquire()
    print "\nSubprocess started"
    p = subprocess.Popen( # etc
    stdout_value = proc.communicate('through stdin to stdout')[0]
    self.lock.release()

对获取和释放的显式调用应该保证序列化 - 如果你在这个块中做其他事情而不是使用子进程,你是不是一直观察序列化?

编辑:这里所有的沉默,所以我会添加删除锁定的建议,而是将每个stdout_value放在Queue.Queue()实例上 - Queue是intrinsicaly线程安全的(处理它自己的锁定)所以你可以get(或get_nowait等)在它们准备就绪后得到put。一般来说,Queue是在Python中安排线程通信(并且通常也是同步)的最佳方式,只要它可以通过这种方式进行可行的安排。

具体来说:在开始时添加import Queue;放弃制作,获取和发布self.lock(只删除这三行);将self.q = Queue.Queue()添加到__init__;在电话stdout_value = proc.communicate(...之后添加一条陈述self.q.put(stdout_value);现在例如用

完成jsonrpc_run_procs方法
while not self.q.empty():
  result = self.q.get()
  print 'One result is %r' % result

确认所有结果都存在。 (通常empty队列的方法不可靠,但在这种情况下,所有放入队列的线程都已经完成,所以你应该没事。“

答案 1 :(得分:1)

您的具体问题可能是由行stdout_value = proc.communicate('through stdin to stdout')[0]引起的。 Subprocess.communicate将"Wait for process to terminate",当与锁一起使用时,将一次运行一个。

您可以做的只是将p变量添加到列表中并运行并使用Subprocess API等待子进程完成。定期轮询主线程中的每个子进程。

再看一下,看起来这行也可能有问题:for th in self.running_threads+self.thread_pool: th.join()。 Thread.join()是另一种等待线程完成的方法。