Python 线程化/生成多个OS命令并在不同点获得输出的最佳方法

Python 线程化/生成多个OS命令并在不同点获得输出的最佳方法,python,subprocess,python-multithreading,python-2.4,Python,Subprocess,Python Multithreading,Python 2.4,我正在努力寻找并行运行多个操作系统命令并能够从中捕获输出的最佳方法。OS命令是一个半长时间运行的专有实用程序,用C语言编写(在solaris/linux主机上运行,使用python 2.4),该脚本将从作业队列中提取作业,为每个作业实例化一个类,然后该类使用提供的参数生成OS实用程序。这个类实际上还有很多内容,但是只关注脚本的整体架构,在这个上下文中省略的代码是微不足道的 实际上有两个点需要这个OS命令的输出 当第一次执行命令时,它返回一个jobid,我需要捕获它。然后,该命令将阻塞,直到完成。

我正在努力寻找并行运行多个操作系统命令并能够从中捕获输出的最佳方法。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()会导致整个线程阻塞,并且我无法在想要的位置获取作业ID

另外,如果我取消对if语句的注释,它会抱怨没有活动的方法()

我尝试过各种不同的方法,比如在类的call方法内部创建线程,但这似乎走错了路

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

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

再次感谢您的帮助。

我认为您可以通过使用
命令
线程继承来简化事情。线程

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
阻塞

然后,您可以调用
communicate
wait
等待进程结束:

self.returncode = self.process.wait()

它抱怨“AttributeError:'Command'对象没有属性'\u lock'”。然后我将其更改为“self.Lock()”并得到相同的错误。在这里使用lock到底有什么意义?Thx。@BenH抱歉,这是复制粘贴错误。现在已修复。我喜欢这种方法,但是“out=self.process.stdout.readline()”似乎也会阻塞:@BenH您不能将其添加为注释。你得把它编辑成你的问题。@BenH是的,有点尴尬。通常提问者会在原始问题的末尾添加一个新的部分,标记为Edit:。