线程/产生多个操作系统命令和获取各点输出的最佳方法

时间:2014-08-06 16:24:27

标签: python subprocess python-multithreading python-2.4

我努力寻找并行运行多个OS命令的最佳方法,并能够捕获它们的输出。 OS命令是用C编写的半长期运行的专有实用程序。(在solaris / linux主机上运行并使用python 2.4)从高级别开始,此脚本将从作业队列中提取作业,为每个作业实例化一个类,其中然后,该类使用提供的参数生成OS实用程序。这个类实际上会有更多,但只关注脚本的整体架构,在这种情况下省略的代码是微不足道的。

实际上有两点需要来自此OS命令的输出。

首次执行命令时,它返回一个我需要捕获的jobid。然后该命令将阻塞直到完成。然后我需要捕获此命令的返回码。

我真正想做的(我认为)是定义一个产生线程然后执行Popen()的类。

以下是我现在所拥有的:

#!/usr/bin/python
import sys, subprocess, threading

cmd = "/path/to/utility -x arg1 -y arg2"

class Command(object):
    def __init__(self, cmd):
        self.cmd        = cmd
        self.process    = None
        self.returncode = None
        self.jobid      = None
    def __call__(self):
        print "Starting job..."
        self.process = subprocess.Popen(self.cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
        out, err = self.process.communicate()
        self.jobid = out.split()[10]

    def alive(self):
        if self.process.poll():
            return True
        else:
            return False

    def getJobID(self):
        return self.jobid


job = Command(cmd)
jobt = threading.Thread(target=job, args=[])
jobt.start()


# if job.alive():
#    print "Job is still alive."
     # do something
# else:
#    print "Job is not alive."
     # do something else

sys.exit(0)

这里的问题是使用p.communicate()会导致整个线程被阻塞,而我无法在我想要的位置获得jobid。

此外,如果我取消注释if语句,它会抱怨没有方法alive()。

我已经尝试了各种变体,比如在类的调用方法中创建线程,但这似乎是我走错了路。

我还尝试在生成线程时将类名指定为目标参数:

jobt = threading.Thread(target=Command, args=[cmd])
jobt.start()

我使用过的每一种方法都让我遇到了障碍。

任何建议都是如此。

所以在尝试了dano的想法后,我现在有了这个:

class Command(threading.Thread):

    def __init__(self, cmd):
        super(Command, self).__init__()
        self.cmd        = cmd
        self.process    = None
        self.returncode = None
        self.jobid      = None

    def run(self):
        print "Starting job..."
        self.process = subprocess.Popen(self.cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, bufsize=0, shell=False) 
        print "Getting job id..."
        out = self.process.stdout.readline()
        print "out=" + out
       self.returncode = self.process.wait()
    def alive(self):
        if self.process.poll():
            return True
        else:
            return False
    def getJobID(self):
        return self.jobid

job = Command(cmd)
job.start()

产生以下输出:

Starting job...
Getting job id...

此时它会挂起,直到OS命令完成。

以下是手动运行此命令的示例。前两行输出立即返回。

$ /path/to/my/command -x arg1 -y arg2
  Info: job request 1 (somestring) submitted; job id is 729.
  Info: waiting for job completion
  # here is hangs until the job is complete
  Info: job 729 completed successfully

再次寻求帮助。

1 个答案:

答案 0 :(得分:1)

我认为您可以通过Command继承threading.Thread来简化事情:

import sys
import subprocess
import threading

cmd = "/path/to/utility -x arg1 -y arg2"

class Command(threading.Thread):
    def __init__(self, cmd):
        super(Command, self).__init__()
        self.cmd = cmd
        self.process = None
        self.returncode = None
        self.jobid = None

    def run(self):
        print "Starting job..."
        self.process = subprocess.Popen(self.cmd, stdout=subprocess.PIPE, 
                                        stderr=subprocess.PIPE, shell=True)
        out, err = self.process.communicate()
        self.jobid = out.split()[10]

    def alive(self):
        if self.process.poll():
            return True
        else:
            return False

    def getJobID(self):
        return self.jobid


job = Command(cmd)
job.start()

if job.alive():
   print "Job is still alive."
else:
   print "Job is not alive."

sys.exit(0)

在命令实际退出之前,您不能使用self.process.communicate()来获取作业ID,因为communicate()将阻塞,直到程序完成。相反,您需要直接从流程“stdout

中使用读取
self.process = subprocess.Popen(self.cmd, stdout=subprocess.PIPE, 
                                stderr=subprocess.PIPE, bufsize=0, shell=True)
out = self.process.stdout.readline()
self.jobid = out.split()[10]

请注意,添加了bufsize=0,因此请尽量避免子进程缓冲其输出,这可能导致readline阻塞。

然后,您可以致电communicatewait等待流程结束:

self.returncode = self.process.wait()